Mesh: Move material indices to a generic attribute

This patch moves material indices from the mesh `MPoly` struct to a
generic integer attribute. The builtin material index was already
exposed in geometry nodes, but this makes it a "proper" attribute
accessible with Python and visible in the "Attributes" panel.

The goals of the refactor are code simplification and memory and
performance improvements, mainly because the attribute doesn't have
to be stored and processed if there are no materials. However, until
4.0, material indices will still be read and written in the old
format, meaning there may be a temporary increase in memory usage.

Further notes:
* Completely removing the `MPoly.mat_nr` after 4.0 may require
  changes to DNA or introducing a new `MPoly` type.
* Geometry nodes regression tests didn't look at material indices,
  so the change reveals a bug in the realize instances node that I fixed.
* Access to material indices from the RNA `MeshPolygon` type is slower
  with this patch. The `material_index` attribute can be used instead.
* Cycles is changed to read from the attribute instead.
* BMesh isn't changed in this patch. Theoretically it could be though,
  to save 2 bytes per face when less than two materials are used.
* Eventually we could use a 16 bit integer attribute type instead.

Ref T95967

Differential Revision: https://developer.blender.org/D15675
This commit is contained in:
2022-08-31 09:09:01 -05:00
parent 3e73afb536
commit f1c0249f34
54 changed files with 664 additions and 300 deletions

View File

@@ -1,6 +1,8 @@
/* SPDX-License-Identifier: Apache-2.0 /* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */ * Copyright 2011-2022 Blender Foundation */
#include <optional>
#include "blender/session.h" #include "blender/session.h"
#include "blender/sync.h" #include "blender/sync.h"
#include "blender/util.h" #include "blender/util.h"
@@ -879,6 +881,23 @@ static void attr_create_random_per_island(Scene *scene,
/* Create Mesh */ /* 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, static void create_mesh(Scene *scene,
Mesh *mesh, Mesh *mesh,
BL::Mesh &b_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 */ /* create faces */
if (!subdivision) { if (!subdivision) {
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) { 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()); 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; bool smooth = p.use_smooth() || use_loop_normals;
if (use_loop_normals) { if (use_loop_normals) {
@@ -977,9 +1005,10 @@ static void create_mesh(Scene *scene,
else { else {
vector<int> vi; 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 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; bool smooth = p.use_smooth() || use_loop_normals;
vi.resize(n); vi.resize(n);

View File

@@ -580,7 +580,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
colliding_names = [] colliding_names = []
for collection in ( for collection in (
# Built-in names. # 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.attributes,
mesh.uv_layers, mesh.uv_layers,
ob.vertex_groups, ob.vertex_groups,

View File

@@ -6,6 +6,9 @@
* \ingroup bke * \ingroup bke
*/ */
#include "DNA_mesh_types.h"
#include "BKE_customdata.h"
#include "BKE_mesh_types.h" #include "BKE_mesh_types.h"
#include "BLI_compiler_attrs.h" #include "BLI_compiler_attrs.h"
#include "BLI_utildefines.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); void BKE_mesh_debug_print(const struct Mesh *me) ATTR_NONNULL(1);
#endif #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 #ifdef __cplusplus
} }
#endif #endif

View File

@@ -27,6 +27,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); 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. * Recreate #MFace Tessellation.
* *

View File

@@ -2375,7 +2375,7 @@ bool CustomData_merge(const CustomData *source,
static bool attribute_stored_in_bmesh_flag(const StringRef name) 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) static CustomData shallow_copy_remove_non_bmesh_attributes(const CustomData &src)

View File

@@ -3247,7 +3247,8 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
mp_example = *mpoly; 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; const char mp_flag = mp_example.flag;
int i; 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. */ /* Loop for triangles. */
for (i = 0; i < num_faces; i++, mpolys++, mloops += 3) { for (i = 0; i < num_faces; i++, mpolys++, mloops += 3) {
/* Initialize from existing face. */ /* Initialize from existing face. */
mpolys->mat_nr = mp_mat_nr; material_indices[i] = mp_mat_nr;
mpolys->flag = mp_flag; mpolys->flag = mp_flag;
mpolys->loopstart = i * 3; mpolys->loopstart = i * 3;

View File

@@ -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) static bool get_shade_smooth(const MPoly &mpoly)
{ {
return mpoly.flag & ME_SMOOTH; return mpoly.flag & ME_SMOOTH;
@@ -1201,17 +1191,16 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
make_array_write_attribute<int>, make_array_write_attribute<int>,
nullptr); nullptr);
static BuiltinCustomDataLayerProvider material_index( static BuiltinCustomDataLayerProvider material_index("material_index",
"material_index",
ATTR_DOMAIN_FACE, ATTR_DOMAIN_FACE,
CD_PROP_INT32, CD_PROP_INT32,
CD_MPOLY, CD_PROP_INT32,
BuiltinAttributeProvider::NonCreatable, BuiltinAttributeProvider::Creatable,
BuiltinAttributeProvider::Writable, BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable, BuiltinAttributeProvider::Deletable,
face_access, face_access,
make_derived_read_attribute<MPoly, int, get_material_index>, make_array_read_attribute<int>,
make_derived_write_attribute<MPoly, int, get_material_index, set_material_index>, make_array_write_attribute<int>,
nullptr); nullptr);
static BuiltinCustomDataLayerProvider shade_smooth( static BuiltinCustomDataLayerProvider shade_smooth(

View File

@@ -35,6 +35,7 @@
#include "BLT_translation.h" #include "BLT_translation.h"
#include "BKE_attribute.hh"
#include "BKE_context.h" #include "BKE_context.h"
#include "BKE_deform.h" #include "BKE_deform.h"
#include "BKE_gpencil.h" #include "BKE_gpencil.h"
@@ -2662,6 +2663,8 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
const bool use_faces, const bool use_faces,
const bool use_vgroups) 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)) { if (ELEM(nullptr, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == nullptr)) {
return false; return false;
} }
@@ -2708,12 +2711,15 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get( bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get(
gpl_fill, scene->r.cfra + frame_offset, GP_GETFRAME_ADD_NEW); gpl_fill, scene->r.cfra + frame_offset, GP_GETFRAME_ADD_NEW);
int i; 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++) { for (i = 0; i < mpoly_len; i++) {
const MPoly *mp = &mpoly[i]; const MPoly *mp = &mpoly[i];
/* Find material. */ /* Find material. */
int mat_idx = 0; 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( make_element_name(
ob_mesh->id.name + 2, (ma != nullptr) ? ma->id.name + 2 : "Fill", 64, 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); mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob_gp, element_name);

View File

@@ -33,6 +33,7 @@
#include "BLI_task.hh" #include "BLI_task.hh"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include "BLI_vector.hh" #include "BLI_vector.hh"
#include "BLI_virtual_array.hh"
#include "BLT_translation.h" #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; Set<std::string> names_to_skip;
if (!BLO_write_is_undo(writer)) { if (!BLO_write_is_undo(writer)) {
BKE_mesh_legacy_convert_hide_layers_to_flags(mesh); 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. */ /* When converting to the old mesh format, don't save redundant attributes. */
names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly"}); 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)) { if (!BLO_read_data_is_undo(reader)) {
BKE_mesh_legacy_convert_flags_to_hide_layers(mesh); 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. */ /* 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) { 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; 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) void BKE_mesh_material_index_remove(Mesh *me, short index)
{ {
MPoly *mp; using namespace blender;
MFace *mf; using namespace blender::bke;
int i; 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()) {
if (indices_span[i] > 0 && indices_span[i] > index) {
indices_span[i]--;
}
}
indices_span.save();
material_indices.finish();
for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { BKE_mesh_tessface_clear(me);
if (mp->mat_nr && mp->mat_nr >= index) {
mp->mat_nr--;
}
}
for (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
if (mf->mat_nr && mf->mat_nr >= index) {
mf->mat_nr--;
}
}
} }
bool BKE_mesh_material_index_used(Mesh *me, short index) bool BKE_mesh_material_index_used(Mesh *me, short index)
{ {
MPoly *mp; using namespace blender;
MFace *mf; using namespace blender::bke;
int i; const AttributeAccessor attributes = mesh_attributes(*me);
const VArray<int> material_indices = attributes.lookup_or_default<int>(
for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { "material_index", ATTR_DOMAIN_FACE, 0);
if (mp->mat_nr == index) { if (material_indices.is_single()) {
return true; return material_indices.get_internal_single() == index;
} }
} const VArraySpan<int> indices_span(material_indices);
return indices_span.contains(index);
for (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
if (mf->mat_nr == index) {
return true;
}
}
return false;
} }
void BKE_mesh_material_index_clear(Mesh *me) void BKE_mesh_material_index_clear(Mesh *me)
{ {
MPoly *mp; using namespace blender;
MFace *mf; using namespace blender::bke;
int i; MutableAttributeAccessor attributes = mesh_attributes_for_write(*me);
attributes.remove("material_index");
for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { BKE_mesh_tessface_clear(me);
mp->mat_nr = 0;
}
for (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
mf->mat_nr = 0;
}
} }
void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) 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; const short remap_len_short = (short)remap_len;
#define MAT_NR_REMAP(n) \ #define MAT_NR_REMAP(n) \
@@ -1490,10 +1490,21 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len)
} }
} }
else { else {
int i; MutableAttributeAccessor attributes = mesh_attributes_for_write(*me);
for (i = 0; i < me->totpoly; i++) { AttributeWriter<int> material_indices = attributes.lookup_for_write<int>("material_index");
MAT_NR_REMAP(me->mpoly[i].mat_nr); 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 #undef MAT_NR_REMAP

View File

@@ -9,6 +9,7 @@
#include "DNA_meshdata_types.h" #include "DNA_meshdata_types.h"
#include "DNA_object_types.h" #include "DNA_object_types.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "BKE_material.h" #include "BKE_material.h"
#include "BKE_mesh.h" #include "BKE_mesh.h"
@@ -23,6 +24,7 @@
#include "BLI_mesh_intersect.hh" #include "BLI_mesh_intersect.hh"
#include "BLI_span.hh" #include "BLI_span.hh"
#include "BLI_task.hh" #include "BLI_task.hh"
#include "BLI_virtual_array.hh"
namespace blender::meshintersect { namespace blender::meshintersect {
@@ -405,13 +407,17 @@ static void copy_poly_attributes(Mesh *dest_mesh,
const Mesh *orig_me, const Mesh *orig_me,
int mp_index, int mp_index,
int index_in_orig_me, 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)) { const VArray<int> src_material_indices = bke::mesh_attributes(*orig_me).lookup_or_default<int>(
mp->mat_nr = material_remap[orig_mp->mat_nr]; "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 { else {
mp->mat_nr = orig_mp->mat_nr; dst_material_indices[mp_index] = src_index;
} }
mp->flag = orig_mp->flag; 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, /* Set the loopstart and totloop for each output poly,
* and set the vertices in the appropriate loops. */ * 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; int cur_loop_index = 0;
MLoop *l = result->mloop; MLoop *l = result->mloop;
for (int fi : im->face_index_range()) { for (int fi : im->face_index_range()) {
@@ -750,9 +759,11 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
index_in_orig_me, index_in_orig_me,
(mim.material_remaps.size() > 0) ? (mim.material_remaps.size() > 0) ?
mim.material_remaps[orig_me_index].as_span() : 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); 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 /* BKE_mesh_calc_edges will calculate and populate all the
* MEdges from the MPolys. */ * MEdges from the MPolys. */

View File

@@ -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) static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispbase)
{ {
using namespace blender::bke;
const float *data; const float *data;
int a, b, ofs, vertcount, startvert, totvert = 0, totedge = 0, totloop = 0, totpoly = 0; int a, b, ofs, vertcount, startvert, totvert = 0, totedge = 0, totloop = 0, totpoly = 0;
int p1, p2, p3, p4, *index; 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(); MEdge *medge = edges.data();
MPoly *mpoly = polys.data(); MPoly *mpoly = polys.data();
MLoop *mloop = loops.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( MLoopUV *mloopuv = static_cast<MLoopUV *>(CustomData_add_layer_named(
&mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, mesh->totloop, "UVMap")); &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]; mloop[2].v = startvert + index[1];
mpoly->loopstart = (int)(mloop - loops.data()); mpoly->loopstart = (int)(mloop - loops.data());
mpoly->totloop = 3; mpoly->totloop = 3;
mpoly->mat_nr = dl->col; material_indices.span[mpoly - polys.data()] = dl->col;
if (mloopuv) { if (mloopuv) {
for (int i = 0; i < 3; i++, 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; mloop[3].v = p2;
mpoly->loopstart = (int)(mloop - loops.data()); mpoly->loopstart = (int)(mloop - loops.data());
mpoly->totloop = 4; mpoly->totloop = 4;
mpoly->mat_nr = dl->col; material_indices.span[mpoly - polys.data()] = dl->col;
if (mloopuv) { if (mloopuv) {
int orco_sizeu = dl->nr - 1; 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); make_edges_mdata_extend(*mesh);
} }
material_indices.finish();
return mesh; return mesh;
} }

View File

@@ -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();
}
}
/** \} */

View File

@@ -24,6 +24,7 @@
#include "BLI_math_vector.h" #include "BLI_math_vector.h"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "BKE_deform.h" #include "BKE_deform.h"
#include "BKE_mesh.h" #include "BKE_mesh.h"
@@ -238,6 +239,10 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
} \ } \
(void)0 (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; MVert *mv = mverts;
MEdge *me; MEdge *me;
MLoop *ml; 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, /* Material index, isolated from other tests here. While large indices are clamped,
* negative indices aren't supported by drawing, exporters etc. * negative indices aren't supported by drawing, exporters etc.
* To check the indices are in range, use #BKE_mesh_validate_material_indices */ * To check the indices are in range, use #BKE_mesh_validate_material_indices */
if (mp->mat_nr < 0) { if (material_indices && material_indices_span[i] < 0) {
PRINT_ERR("\tPoly %u has invalid material (%d)", sp->index, mp->mat_nr); PRINT_ERR("\tPoly %u has invalid material (%d)", sp->index, material_indices_span[i]);
if (do_fixes) { 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__); PRINT_MSG("%s: finished\n\n", __func__);
*r_changed = (fix_flag.as_flag || free_flag.as_flag || recalc_flag.as_flag); *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) bool BKE_mesh_validate_material_indices(Mesh *me)
{ {
/* Cast to unsigned to catch negative indices too. */ const int mat_nr_max = max_ii(0, me->totcol - 1);
const uint16_t mat_nr_max = max_ii(0, me->totcol - 1);
MPoly *mp;
const int totpoly = me->totpoly;
int i;
bool is_valid = true; bool is_valid = true;
for (mp = me->mpoly, i = 0; i < totpoly; i++, mp++) { blender::bke::AttributeWriter<int> material_indices =
if ((uint16_t)mp->mat_nr > mat_nr_max) { blender::bke::mesh_attributes_for_write(*me).lookup_for_write<int>("material_index");
mp->mat_nr = 0; 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; is_valid = false;
} }
} }
material_indices_span.save();
material_indices.finish();
if (!is_valid) { if (!is_valid) {
DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY_ALL_MODES); DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY_ALL_MODES);

View File

@@ -145,9 +145,14 @@ static void update_node_vb(PBVH *pbvh, PBVHNode *node)
// BB_expand(&node->vb, co); // 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) 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 */ /* Returns the index of the first element on the right of the partition */
static int partition_indices_material(PBVH *pbvh, int lo, int hi) static int partition_indices_material(PBVH *pbvh, int lo, int hi)
{ {
const MPoly *mpoly = pbvh->mpoly;
const MLoopTri *looptri = pbvh->looptri; const MLoopTri *looptri = pbvh->looptri;
const DMFlagMat *flagmats = pbvh->grid_flag_mats; const DMFlagMat *flagmats = pbvh->grid_flag_mats;
const int *indices = pbvh->prim_indices; const int *indices = pbvh->prim_indices;
const void *first;
int i = lo, j = hi; int i = lo, j = hi;
if (pbvh->looptri) {
first = &mpoly[looptri[pbvh->prim_indices[lo]].poly];
}
else {
first = &flagmats[pbvh->prim_indices[lo]];
}
for (;;) { for (;;) {
if (pbvh->looptri) { 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 */ /* pass */
} }
for (; !face_materials_match(first, &mpoly[looptri[indices[j]].poly]); j--) { for (; !face_materials_match(pbvh, first, looptri[indices[j]].poly); j--) {
/* pass */ /* pass */
} }
} }
else { else {
const DMFlagMat *first = &flagmats[pbvh->prim_indices[lo]];
for (; grid_materials_match(first, &flagmats[indices[i]]); i++) { for (; grid_materials_match(first, &flagmats[indices[i]]); i++) {
/* pass */ /* pass */
} }
@@ -424,12 +422,9 @@ static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count)
if (pbvh->looptri) { if (pbvh->looptri) {
const MLoopTri *first = &pbvh->looptri[pbvh->prim_indices[offset]]; 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--) { for (int i = offset + count - 1; i > offset; i--) {
int prim = pbvh->prim_indices[i]; int prim = pbvh->prim_indices[i];
const MPoly *mp_other = &pbvh->mpoly[pbvh->looptri[prim].poly]; if (!face_materials_match(pbvh, first->poly, pbvh->looptri[prim].poly)) {
if (!face_materials_match(mp, mp_other)) {
return true; return true;
} }
} }
@@ -557,6 +552,8 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
pbvh->mesh = mesh; pbvh->mesh = mesh;
pbvh->header.type = PBVH_FACES; pbvh->header.type = PBVH_FACES;
pbvh->mpoly = mpoly; pbvh->mpoly = mpoly;
pbvh->material_indices = (const int *)CustomData_get_layer_named(
&mesh->pdata, CD_PROP_INT32, "material_index");
pbvh->mloop = mloop; pbvh->mloop = mloop;
pbvh->looptri = looptri; pbvh->looptri = looptri;
pbvh->verts = verts; pbvh->verts = verts;

View File

@@ -156,6 +156,8 @@ struct PBVH {
bool *hide_vert; bool *hide_vert;
struct MVert *verts; struct MVert *verts;
const struct MPoly *mpoly; const struct MPoly *mpoly;
/** Material indices. Only valid for polygon meshes. */
const int *material_indices;
const struct MLoop *mloop; const struct MLoop *mloop;
const struct MLoopTri *looptri; const struct MLoopTri *looptri;
CustomData *vdata; CustomData *vdata;

View File

@@ -5,6 +5,7 @@
* \ingroup bke * \ingroup bke
*/ */
#include "BKE_customdata.h"
#include "BKE_subdiv_ccg.h" #include "BKE_subdiv_ccg.h"
#include "MEM_guardedalloc.h" #include "MEM_guardedalloc.h"
@@ -14,6 +15,7 @@
typedef struct CCGMaterialFromMeshData { typedef struct CCGMaterialFromMeshData {
const Mesh *mesh; const Mesh *mesh;
const int *material_indices;
} CCGMaterialFromMeshData; } CCGMaterialFromMeshData;
static DMFlagMat subdiv_ccg_material_flags_eval( 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]; const MPoly *poly = &mpoly[coarse_face_index];
DMFlagMat material_flags; DMFlagMat material_flags;
material_flags.flag = poly->flag; 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; return material_flags;
} }
@@ -42,6 +44,8 @@ void BKE_subdiv_ccg_material_flags_init_from_mesh(
CCGMaterialFromMeshData *data = MEM_mallocN(sizeof(CCGMaterialFromMeshData), CCGMaterialFromMeshData *data = MEM_mallocN(sizeof(CCGMaterialFromMeshData),
"ccg material eval"); "ccg material eval");
data->mesh = mesh; 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->eval_material_flags = subdiv_ccg_material_flags_eval;
material_flags_evaluator->free = subdiv_ccg_material_flags_free; material_flags_evaluator->free = subdiv_ccg_material_flags_free;
material_flags_evaluator->user_data = data; material_flags_evaluator->user_data = data;

View File

@@ -1134,14 +1134,12 @@ static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *mpoly)
CCGFace *f = ccgdm->faceMap[index].face; CCGFace *f = ccgdm->faceMap[index].face;
int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
int flag = (faceFlags) ? faceFlags[index].flag : ME_SMOOTH; int flag = (faceFlags) ? faceFlags[index].flag : ME_SMOOTH;
int mat_nr = (faceFlags) ? faceFlags[index].mat_nr : 0;
for (S = 0; S < numVerts; S++) { for (S = 0; S < numVerts; S++) {
for (y = 0; y < gridSize - 1; y++) { for (y = 0; y < gridSize - 1; y++) {
for (x = 0; x < gridSize - 1; x++) { for (x = 0; x < gridSize - 1; x++) {
MPoly *mp = &mpoly[i]; MPoly *mp = &mpoly[i];
mp->mat_nr = mat_nr;
mp->flag = flag; mp->flag = flag;
mp->loopstart = k; mp->loopstart = k;
mp->totloop = 4; mp->totloop = 4;
@@ -1607,6 +1605,8 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
medge = dm->getEdgeArray(dm); medge = dm->getEdgeArray(dm);
const MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); 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); const int *base_polyOrigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
int *vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, 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; ccgdm->faceMap[index].startFace = faceNum;
faceFlags->flag = mpoly ? mpoly[origIndex].flag : 0; 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++; faceFlags++;
/* set the face base vert */ /* set the face base vert */

View File

@@ -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`. * set. If this is not necessarily the case, use `index_of_try`.
*/ */
int64_t index_of(const Key &key) const int64_t index_of(const Key &key) const

View File

@@ -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"); &me->edata, CD_PROP_BOOL, ".hide_edge");
const bool *hide_poly = (const bool *)CustomData_get_layer_named( const bool *hide_poly = (const bool *)CustomData_get_layer_named(
&me->pdata, CD_PROP_BOOL, ".hide_poly"); &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}; Span<MVert> mvert{me->mvert, me->totvert};
Array<BMVert *> vtable(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); 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) { if (i == me->act_face) {
bm->act_face = f; bm->act_face = f;
} }
@@ -923,8 +925,8 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
} }
} }
template<typename GetFn> template<typename T, typename GetFn>
static void write_elem_flag_to_attribute(blender::bke::MutableAttributeAccessor &attributes, static void write_fn_to_attribute(blender::bke::MutableAttributeAccessor attributes,
const StringRef attribute_name, const StringRef attribute_name,
const eAttrDomain domain, const eAttrDomain domain,
const bool do_write, const bool do_write,
@@ -932,7 +934,7 @@ static void write_elem_flag_to_attribute(blender::bke::MutableAttributeAccessor
{ {
using namespace blender; using namespace blender;
if (do_write) { 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); attribute_name, domain);
threading::parallel_for(attribute.span.index_range(), 4096, [&](IndexRange range) { threading::parallel_for(attribute.span.index_range(), 4096, [&](IndexRange range) {
for (const int i : 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); bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh);
BM_mesh_elem_table_ensure(&bm, BM_VERT | BM_EDGE | BM_FACE); 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) { 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); 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) { 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); 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) { 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); 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_vert = false;
bool need_hide_edge = false; bool need_hide_edge = false;
bool need_hide_poly = 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 /* Clear normals on the mesh completely, since the original vertex and polygon count might be
* different than the BMesh's. */ * 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; BMLoop *l_iter, *l_first;
mpoly->loopstart = j; mpoly->loopstart = j;
mpoly->totloop = f->len; 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); mpoly->flag = BM_face_flag_to_mflag(f);
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
need_hide_poly = true; 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); 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. */ /* Patch hook indices and vertex parents. */
if (params->calc_object_remap && (ototvert > 0)) { if (params->calc_object_remap && (ototvert > 0)) {
BLI_assert(bmain != nullptr); 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_vert = false;
bool need_hide_edge = false; bool need_hide_edge = false;
bool need_hide_poly = 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 /* Clear normals on the mesh completely, since the original vertex and polygon count might be
* different than the BMesh's. */ * 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->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); l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
do { 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); 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( convert_bmesh_hide_flags_to_mesh_attributes(
*bm, need_hide_vert, need_hide_edge, need_hide_poly, *me); *bm, need_hide_vert, need_hide_edge, need_hide_poly, *me);

View File

@@ -14,6 +14,7 @@
#include "BLI_math.h" #include "BLI_math.h"
#include "BLI_task.h" #include "BLI_task.h"
#include "BKE_attribute.hh"
#include "BKE_editmesh.h" #include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h" #include "BKE_editmesh_cache.h"
#include "BKE_mesh.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++) { for (int i = 0; i < mr->poly_len; i++) {
if (!(mr->use_hide && mr->hide_poly && mr->hide_poly[i])) { if (!(mr->use_hide && mr->hide_poly && mr->hide_poly[i])) {
const MPoly *mp = &mr->mpoly[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]; tri_first_index[i] = mat_tri_offs[mat];
mat_tri_offs[mat] += mp->totloop - 2; 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]; const MPoly *mp = &mr->mpoly[iter];
if (!(mr->use_hide && mr->hide_poly && mr->hide_poly[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; 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->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->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 *>( mr->hide_vert = static_cast<const bool *>(
CustomData_get_layer_named(&me->vdata, CD_PROP_BOOL, ".hide_vert")); CustomData_get_layer_named(&me->vdata, CD_PROP_BOOL, ".hide_vert"));
mr->hide_edge = static_cast<const bool *>( mr->hide_edge = static_cast<const bool *>(

View File

@@ -7,6 +7,7 @@
#include "DNA_object_types.h" #include "DNA_object_types.h"
#include "DNA_scene_types.h" #include "DNA_scene_types.h"
#include "BKE_attribute.hh"
#include "BKE_editmesh.h" #include "BKE_editmesh.h"
#include "BKE_mesh.h" #include "BKE_mesh.h"
#include "BKE_modifier.h" #include "BKE_modifier.h"
@@ -19,8 +20,8 @@
#include "BKE_subdiv_modifier.h" #include "BKE_subdiv_modifier.h"
#include "BLI_linklist.h" #include "BLI_linklist.h"
#include "BLI_string.h" #include "BLI_string.h"
#include "BLI_virtual_array.hh"
#include "PIL_time.h" #include "PIL_time.h"
@@ -1962,17 +1963,20 @@ static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache,
return; 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. */ /* Count number of subdivided polygons for each material. */
int *mat_start = static_cast<int *>(MEM_callocN(sizeof(int) * mat_len, "subdiv mat_start")); int *mat_start = static_cast<int *>(MEM_callocN(sizeof(int) * mat_len, "subdiv mat_start"));
int *subdiv_polygon_offset = cache->subdiv_polygon_offset; int *subdiv_polygon_offset = cache->subdiv_polygon_offset;
/* TODO: parallel_reduce? */ /* TODO: parallel_reduce? */
for (int i = 0; i < mesh_eval->totpoly; i++) { 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 : const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads :
subdiv_polygon_offset[i + 1]; subdiv_polygon_offset[i + 1];
const int quad_count = next_offset - subdiv_polygon_offset[i]; 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; 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")); MEM_mallocN(sizeof(int) * mesh_eval->totpoly, "per_polygon_mat_offset"));
for (int i = 0; i < mesh_eval->totpoly; i++) { for (int i = 0; i < mesh_eval->totpoly; i++) {
const MPoly *mpoly = &mesh_eval->mpoly[i]; const int mat_index = material_indices[i];
const int mat_index = mpoly->mat_nr;
const int single_material_index = subdiv_polygon_offset[i]; const int single_material_index = subdiv_polygon_offset[i];
const int material_offset = mat_end[mat_index]; const int material_offset = mat_end[mat_index];
const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads : const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads :

View File

@@ -80,6 +80,7 @@ struct MeshRenderData {
BMFace *efa_act_uv; BMFace *efa_act_uv;
/* Data created on-demand (usually not for #BMesh based data). */ /* Data created on-demand (usually not for #BMesh based data). */
MLoopTri *mlooptri; MLoopTri *mlooptri;
const int *material_indices;
const float (*vert_normals)[3]; const float (*vert_normals)[3];
const float (*poly_normals)[3]; const float (*poly_normals)[3];
const bool *hide_vert; const bool *hide_vert;

View File

@@ -10,6 +10,8 @@
#include "MEM_guardedalloc.h" #include "MEM_guardedalloc.h"
#include "BLI_virtual_array.hh"
#include "DNA_key_types.h" #include "DNA_key_types.h"
#include "DNA_material_types.h" #include "DNA_material_types.h"
#include "DNA_mesh_types.h" #include "DNA_mesh_types.h"
@@ -21,6 +23,7 @@
#include "DNA_view3d_types.h" #include "DNA_view3d_types.h"
#include "DNA_workspace_types.h" #include "DNA_workspace_types.h"
#include "BKE_attribute.hh"
#include "BKE_context.h" #include "BKE_context.h"
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "BKE_deform.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_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly);
CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->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++) { for (a = 0; a < me->totpoly; a++, mpoly++) {
mpoly->loopstart += *loopofs; mpoly->loopstart += *loopofs;
mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0;
} }
/* Face maps. */ /* Face maps. */

View File

@@ -161,9 +161,10 @@ static bool multiresbake_check(bContext *C, wmOperator *op)
ok = false; ok = false;
} }
else { else {
const int *material_indices = BKE_mesh_material_indices(me);
a = me->totpoly; a = me->totpoly;
while (ok && a--) { 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) { if (!ima) {
BKE_report( BKE_report(

View File

@@ -414,6 +414,7 @@ typedef struct ProjPaintState {
const float (*vert_normals)[3]; const float (*vert_normals)[3];
const MEdge *medge_eval; const MEdge *medge_eval;
const MPoly *mpoly_eval; const MPoly *mpoly_eval;
const int *material_indices;
const MLoop *mloop_eval; const MLoop *mloop_eval;
const MLoopTri *mlooptri_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) static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int tri_index)
{ {
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index); const int poly_i = ps->mlooptri_eval[tri_index].poly;
Material *ma = ps->mat_array[mp->mat_nr]; Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]];
return ma ? ma->texpaintslot + ma->paint_active_slot : NULL; 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; return ps->stencil_ima;
} }
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index); const int poly_i = ps->mlooptri_eval[tri_index].poly;
Material *ma = ps->mat_array[mp->mat_nr]; 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; TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
return slot ? slot->ima : ps->canvas_ima; return slot ? slot->ima : ps->canvas_ima;
} }
static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int tri_index) static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int tri_index)
{ {
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index); const int poly_i = ps->mlooptri_eval[tri_index].poly;
Material *ma = ps->mat_array[mp->mat_nr]; Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]];
return ma ? ma->texpaintslot + ma->paint_clone_slot : NULL; return ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
} }
static Image *project_paint_face_clone_image(const ProjPaintState *ps, int tri_index) static Image *project_paint_face_clone_image(const ProjPaintState *ps, int tri_index)
{ {
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index); const int poly_i = ps->mlooptri_eval[tri_index].poly;
Material *ma = ps->mat_array[mp->mat_nr]; 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; TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
return slot ? slot->ima : ps->clone_ima; 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->mloop_eval = ps->me_eval->mloop;
ps->mpoly_eval = ps->me_eval->mpoly; 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->totvert_eval = ps->me_eval->totvert;
ps->totedge_eval = ps->me_eval->totedge; ps->totedge_eval = ps->me_eval->totedge;

View File

@@ -287,7 +287,6 @@ static void imapaint_pick_uv(
const int tottri = me_eval->runtime.looptris.len; const int tottri = me_eval->runtime.looptris.len;
const MVert *mvert = me_eval->mvert; const MVert *mvert = me_eval->mvert;
const MPoly *mpoly = me_eval->mpoly;
const MLoop *mloop = me_eval->mloop; const MLoop *mloop = me_eval->mloop;
const int *index_mp_to_orig = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX); 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; minabsw = 1e10;
uv[0] = uv[1] = 0.0; 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 */ /* test all faces in the derivedmesh with the original index of the picked face */
/* face means poly here, not triangle, indeed */ /* face means poly here, not triangle, indeed */
for (i = 0; i < tottri; i++, lt++) { for (i = 0; i < tottri; i++, lt++) {
@@ -309,7 +311,6 @@ static void imapaint_pick_uv(
if (findex == faceindex) { if (findex == faceindex) {
const MLoopUV *mloopuv; const MLoopUV *mloopuv;
const MPoly *mp = &mpoly[lt->poly];
const MLoopUV *tri_uv[3]; const MLoopUV *tri_uv[3];
float tri_co[3][3]; float tri_co[3][3];
@@ -321,7 +322,8 @@ static void imapaint_pick_uv(
const Material *ma; const Material *ma;
const TexPaintSlot *slot; 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]; slot = &ma->texpaintslot[ma->paint_active_slot];
if (!(slot && slot->uvname && if (!(slot && slot->uvname &&
@@ -410,6 +412,8 @@ void paint_sample_color(
cddata_masks.pmask |= CD_MASK_ORIGINDEX; cddata_masks.pmask |= CD_MASK_ORIGINDEX;
Mesh *me = (Mesh *)ob->data; Mesh *me = (Mesh *)ob->data;
Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob_eval, &cddata_masks); 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; ViewContext vc;
const int mval[2] = {x, y}; const int mval[2] = {x, y};
@@ -427,8 +431,8 @@ void paint_sample_color(
if (use_material) { if (use_material) {
/* Image and texture interpolation from material. */ /* Image and texture interpolation from material. */
MPoly *mp = me_eval->mpoly + faceindex; Material *ma = BKE_object_material_get(
Material *ma = BKE_object_material_get(ob_eval, mp->mat_nr + 1); ob_eval, material_indices ? material_indices[faceindex] + 1 : 1);
/* Force refresh since paint slots are not updated when changing interpolation. */ /* Force refresh since paint slots are not updated when changing interpolation. */
BKE_texpaint_slot_refresh_cache(scene, ma, ob); BKE_texpaint_slot_refresh_cache(scene, ma, ob);

View File

@@ -8,6 +8,7 @@
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include "BKE_attribute.hh"
#include "BKE_global.h" #include "BKE_global.h"
#include "BKE_object.h" #include "BKE_object.h"
@@ -497,12 +498,16 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
FrsMaterial tmpMat; 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 // We parse the vlak nodes again and import meshes while applying the clipping
// by the near and far view planes. // by the near and far view planes.
for (int a = 0; a < tottri; a++) { for (int a = 0; a < tottri; a++) {
const MLoopTri *lt = &mlooptri[a]; const MLoopTri *lt = &mlooptri[a];
const MPoly *mp = &mpoly[lt->poly]; 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(v1, mvert[mloop[lt->tri[0]].v].co);
copy_v3_v3(v2, mvert[mloop[lt->tri[1]].v].co); copy_v3_v3(v2, mvert[mloop[lt->tri[1]].v].co);

View File

@@ -584,7 +584,8 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly); &mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly);
mesh->mloop = (MLoop *)CustomData_add_layer( mesh->mloop = (MLoop *)CustomData_add_layer(
&mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop); &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; MVert *vertices = mesh->mvert;
MEdge *edges = mesh->medge; MEdge *edges = mesh->medge;
MPoly *polys = mesh->mpoly; MPoly *polys = mesh->mpoly;
@@ -714,7 +715,8 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
// poly // poly
polys->loopstart = loop_index; polys->loopstart = loop_index;
polys->totloop = 3; polys->totloop = 3;
polys->mat_nr = matnr; *material_indices = matnr;
++material_indices;
++polys; ++polys;
// Even and odd loops connect triangles vertices differently // Even and odd loops connect triangles vertices differently

View File

@@ -9,6 +9,7 @@
#include "DNA_object_types.h" #include "DNA_object_types.h"
#include "DNA_pointcloud_types.h" #include "DNA_pointcloud_types.h"
#include "BLI_devirtualize_parameters.hh"
#include "BLI_noise.hh" #include "BLI_noise.hh"
#include "BLI_task.hh" #include "BLI_task.hh"
@@ -102,6 +103,7 @@ struct MeshRealizeInfo {
Array<std::optional<GVArraySpan>> attributes; Array<std::optional<GVArraySpan>> attributes;
/** Vertex ids stored on the mesh. If there are no ids, this #Span is empty. */ /** Vertex ids stored on the mesh. If there are no ids, this #Span is empty. */
Span<int> stored_vertex_ids; Span<int> stored_vertex_ids;
VArray<int> material_indices;
}; };
struct RealizeMeshTask { struct RealizeMeshTask {
@@ -182,6 +184,7 @@ struct AllMeshesInfo {
/** Ordered materials on the output mesh. */ /** Ordered materials on the output mesh. */
VectorSet<Material *> materials; VectorSet<Material *> materials;
bool create_id_attribute = false; bool create_id_attribute = false;
bool create_material_index_attribute = false;
}; };
struct AllCurvesInfo { struct AllCurvesInfo {
@@ -787,7 +790,10 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti
* \{ */ * \{ */
static OrderedAttributes gather_generic_mesh_attributes_to_propagate( 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; Vector<GeometryComponentType> src_component_types;
src_component_types.append(GEO_COMPONENT_TYPE_MESH); 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); src_component_types, GEO_COMPONENT_TYPE_MESH, true, attributes_to_propagate);
attributes_to_propagate.remove("position"); attributes_to_propagate.remove("position");
attributes_to_propagate.remove("normal"); attributes_to_propagate.remove("normal");
attributes_to_propagate.remove("material_index");
attributes_to_propagate.remove("shade_smooth"); attributes_to_propagate.remove("shade_smooth");
attributes_to_propagate.remove("crease"); attributes_to_propagate.remove("crease");
r_create_id = attributes_to_propagate.pop_try("id").has_value(); 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; OrderedAttributes ordered_attributes;
for (const auto item : attributes_to_propagate.items()) { for (const auto item : attributes_to_propagate.items()) {
ordered_attributes.ids.add_new(item.key); ordered_attributes.ids.add_new(item.key);
@@ -833,15 +839,21 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
{ {
AllMeshesInfo info; AllMeshesInfo info;
info.attributes = gather_generic_mesh_attributes_to_propagate( 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); gather_meshes_to_realize(geometry_set, info.order);
for (const Mesh *mesh : info.order) { for (const Mesh *mesh : info.order) {
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)) { for (const int slot_index : IndexRange(mesh->totcol)) {
Material *material = mesh->mat[slot_index]; Material *material = mesh->mat[slot_index];
info.materials.add(material); info.materials.add(material);
} }
} }
}
info.realize_info.reinitialize(info.order.size()); info.realize_info.reinitialize(info.order.size());
for (const int mesh_index : info.realize_info.index_range()) { for (const int mesh_index : info.realize_info.index_range()) {
MeshRealizeInfo &mesh_info = info.realize_info[mesh_index]; MeshRealizeInfo &mesh_info = info.realize_info[mesh_index];
@@ -849,12 +861,17 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
mesh_info.mesh = mesh; mesh_info.mesh = mesh;
/* Create material index mapping. */ /* Create material index mapping. */
mesh_info.material_index_map.reinitialize(mesh->totcol); 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)) { for (const int old_slot_index : IndexRange(mesh->totcol)) {
Material *material = mesh->mat[old_slot_index]; Material *material = mesh->mat[old_slot_index];
const int new_slot_index = info.materials.index_of(material); 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[old_slot_index] = new_slot_index;
} }
}
/* Access attributes. */ /* Access attributes. */
bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh); bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh);
@@ -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.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; return info;
} }
@@ -883,7 +902,8 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
const OrderedAttributes &ordered_attributes, const OrderedAttributes &ordered_attributes,
Mesh &dst_mesh, Mesh &dst_mesh,
MutableSpan<GSpanAttributeWriter> dst_attribute_writers, 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 MeshRealizeInfo &mesh_info = *task.mesh_info;
const Mesh &mesh = *mesh_info.mesh; 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<MLoop> src_loops{mesh.mloop, mesh.totloop};
const Span<MPoly> src_polys{mesh.mpoly, mesh.totpoly}; const Span<MPoly> src_polys{mesh.mpoly, mesh.totpoly};
MutableSpan<MVert> dst_verts{dst_mesh.mvert + task.start_indices.vertex, mesh.totvert}; const IndexRange dst_vert_range(task.start_indices.vertex, src_verts.size());
MutableSpan<MEdge> dst_edges{dst_mesh.medge + task.start_indices.edge, mesh.totedge}; const IndexRange dst_edge_range(task.start_indices.edge, src_edges.size());
MutableSpan<MLoop> dst_loops{dst_mesh.mloop + task.start_indices.loop, mesh.totloop}; const IndexRange dst_poly_range(task.start_indices.poly, src_polys.size());
MutableSpan<MPoly> dst_polys{dst_mesh.mpoly + task.start_indices.poly, mesh.totpoly}; 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; 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) { for (const int i : vert_range) {
const MVert &src_vert = src_verts[i]; const MVert &src_vert = src_verts[i];
MVert &dst_vert = dst_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)); 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) { for (const int i : edge_range) {
const MEdge &src_edge = src_edges[i]; const MEdge &src_edge = src_edges[i];
MEdge &dst_edge = dst_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; 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) { for (const int i : loop_range) {
const MLoop &src_loop = src_loops[i]; const MLoop &src_loop = src_loops[i];
MLoop &dst_loop = dst_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; 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) { for (const int i : poly_range) {
const MPoly &src_poly = src_polys[i]; const MPoly &src_poly = src_polys[i];
MPoly &dst_poly = dst_polys[i]; MPoly &dst_poly = dst_polys[i];
dst_poly = src_poly; dst_poly = src_poly;
dst_poly.loopstart += task.start_indices.loop; 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];
}
else {
/* The material index was invalid before. */
dst_poly.mat_nr = 0;
}
} }
}); });
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 {
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()) { if (!all_dst_vertex_ids.is_empty()) {
create_result_ids(options, create_result_ids(options,
@@ -956,13 +998,13 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
[&](const eAttrDomain domain) { [&](const eAttrDomain domain) {
switch (domain) { switch (domain) {
case ATTR_DOMAIN_POINT: case ATTR_DOMAIN_POINT:
return IndexRange(task.start_indices.vertex, mesh.totvert); return dst_vert_range;
case ATTR_DOMAIN_EDGE: case ATTR_DOMAIN_EDGE:
return IndexRange(task.start_indices.edge, mesh.totedge); return dst_edge_range;
case ATTR_DOMAIN_CORNER:
return IndexRange(task.start_indices.loop, mesh.totloop);
case ATTR_DOMAIN_FACE: 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: default:
BLI_assert_unreachable(); BLI_assert_unreachable();
return IndexRange(); return IndexRange();
@@ -1013,6 +1055,12 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
if (all_meshes_info.create_id_attribute) { if (all_meshes_info.create_id_attribute) {
vertex_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT); 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. */ /* Prepare generic output attributes. */
Vector<GSpanAttributeWriter> dst_attribute_writers; 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) { threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
for (const int task_index : task_range) { for (const int task_index : task_range) {
const RealizeMeshTask &task = tasks[task_index]; const RealizeMeshTask &task = tasks[task_index];
execute_realize_mesh_task( execute_realize_mesh_task(options,
options, task, ordered_attributes, *dst_mesh, dst_attribute_writers, vertex_ids.span); 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) { if (vertex_ids) {
vertex_ids.finish(); vertex_ids.finish();
} }
if (material_indices) {
material_indices.finish();
}
} }
/** \} */ /** \} */

View File

@@ -1472,6 +1472,7 @@ typedef struct EdgeFeatData {
Mesh *me; Mesh *me;
Object *ob_eval; /* For evaluated materials. */ Object *ob_eval; /* For evaluated materials. */
const MLoopTri *mlooptri; const MLoopTri *mlooptri;
const int *material_indices;
LineartTriangle *tri_array; LineartTriangle *tri_array;
LineartVert *v_array; LineartVert *v_array;
float crease_threshold; float crease_threshold;
@@ -1503,6 +1504,7 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
EdgeFeatData *e_feat_data = (EdgeFeatData *)userdata; EdgeFeatData *e_feat_data = (EdgeFeatData *)userdata;
EdgeFeatReduceData *reduce_data = (EdgeFeatReduceData *)tls->userdata_chunk; EdgeFeatReduceData *reduce_data = (EdgeFeatReduceData *)tls->userdata_chunk;
Mesh *me = e_feat_data->me; Mesh *me = e_feat_data->me;
const int *material_indices = e_feat_data->material_indices;
Object *ob_eval = e_feat_data->ob_eval; Object *ob_eval = e_feat_data->ob_eval;
LineartEdgeNeighbor *edge_nabr = e_feat_data->edge_nabr; LineartEdgeNeighbor *edge_nabr = e_feat_data->edge_nabr;
const MLoopTri *mlooptri = e_feat_data->mlooptri; 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 mat1 = material_indices ? material_indices[mlooptri[f1].poly] : 0;
int mat2 = me->mpoly[mlooptri[f2].poly].mat_nr; int mat2 = material_indices ? material_indices[mlooptri[f2].poly] : 0;
if (mat1 != mat2) { if (mat1 != mat2) {
Material *m1 = BKE_object_material_get_eval(ob_eval, mat1 + 1); 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 { typedef struct TriData {
LineartObjectInfo *ob_info; LineartObjectInfo *ob_info;
const MLoopTri *mlooptri; const MLoopTri *mlooptri;
const int *material_indices;
LineartVert *vert_arr; LineartVert *vert_arr;
LineartTriangle *tri_arr; LineartTriangle *tri_arr;
int lineart_triangle_size; 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; Mesh *me = tri_task_data->ob_info->original_me;
LineartObjectInfo *ob_info = tri_task_data->ob_info; LineartObjectInfo *ob_info = tri_task_data->ob_info;
const MLoopTri *mlooptri = &tri_task_data->mlooptri[i]; 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; LineartVert *vert_arr = tri_task_data->vert_arr;
LineartTriangle *tri = tri_task_data->tri_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]; tri->v[2] = &vert_arr[v3];
/* Material mask bits and occlusion effectiveness assignment. */ /* Material mask bits and occlusion effectiveness assignment. */
Material *mat = BKE_object_material_get_eval(ob_info->original_ob_eval, Material *mat = BKE_object_material_get(
me->mpoly[mlooptri->poly].mat_nr + 1); 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)) ? tri->material_mask_bits |= ((mat && (mat->lineart.flags & LRT_MATERIAL_MASK_ENABLED)) ?
mat->lineart.material_mask_bits : mat->lineart.material_mask_bits :
0); 0);
@@ -1992,6 +1996,9 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me); const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me);
const int tot_tri = BKE_mesh_runtime_looptri_len(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. */ /* Check if we should look for custom data tags like Freestyle edges or faces. */
bool can_find_freestyle_edge = false; bool can_find_freestyle_edge = false;
int layer_index = CustomData_get_active_layer_index(&me->edata, CD_FREESTYLE_EDGE); 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; TriData tri_data;
tri_data.ob_info = ob_info; tri_data.ob_info = ob_info;
tri_data.mlooptri = mlooptri; tri_data.mlooptri = mlooptri;
tri_data.material_indices = material_indices;
tri_data.vert_arr = la_v_arr; tri_data.vert_arr = la_v_arr;
tri_data.tri_arr = la_tri_arr; tri_data.tri_arr = la_tri_arr;
tri_data.lineart_triangle_size = la_data->sizeof_triangle; 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.me = me;
edge_feat_data.ob_eval = ob_info->original_ob_eval; edge_feat_data.ob_eval = ob_info->original_ob_eval;
edge_feat_data.mlooptri = mlooptri; 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.edge_nabr = lineart_build_edge_neighbor(me, total_edges);
edge_feat_data.tri_array = la_tri_arr; edge_feat_data.tri_array = la_tri_arr;
edge_feat_data.v_array = la_v_arr; edge_feat_data.v_array = la_v_arr;

View File

@@ -233,8 +233,10 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
GPUAttrRef vcol_refs[MAX_GPU_ATTR]; GPUAttrRef vcol_refs[MAX_GPU_ATTR];
GPUAttrRef cd_uvs[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"); &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); const CustomDataLayer *actcol = BKE_id_attributes_active_color_get(&mesh->id);
eAttrDomain actcol_domain = actcol ? BKE_id_attribute_domain(&mesh->id, actcol) : 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. */ /* Get material index from the first face of this buffer. */
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]]; const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]];
const MPoly *mp = &buffers->mpoly[lt->poly]; buffers->material_index = material_indices ? material_indices[lt->poly] : 0;
buffers->material_index = mp->mat_nr;
buffers->show_overlay = !empty_mask || !default_face_set; buffers->show_overlay = !empty_mask || !default_face_set;
buffers->mvert = mvert; buffers->mvert = mvert;

View File

@@ -12,6 +12,7 @@
#include "BLI_math_vector.h" #include "BLI_math_vector.h"
#include "BKE_attribute.h" #include "BKE_attribute.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "BKE_lib_id.h" #include "BKE_lib_id.h"
#include "BKE_material.h" #include "BKE_material.h"
@@ -390,12 +391,12 @@ void ABCGenericMeshWriter::get_geo_groups(Object *object,
struct Mesh *mesh, struct Mesh *mesh,
std::map<std::string, std::vector<int32_t>> &geo_groups) std::map<std::string, std::vector<int32_t>> &geo_groups)
{ {
const int num_poly = mesh->totpoly; const bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh);
MPoly *polygons = mesh->mpoly; const VArraySpan<int> material_indices = attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
for (int i = 0; i < num_poly; i++) { for (const int i : material_indices.index_range()) {
MPoly &current_poly = polygons[i]; short mnr = material_indices[i];
short mnr = current_poly.mat_nr;
Material *mat = BKE_object_material_get(object, mnr + 1); Material *mat = BKE_object_material_get(object, mnr + 1);

View File

@@ -25,7 +25,7 @@
#include "BLI_listbase.h" #include "BLI_listbase.h"
#include "BLI_math_geom.h" #include "BLI_math_geom.h"
#include "BKE_attribute.h" #include "BKE_attribute.hh"
#include "BKE_main.h" #include "BKE_main.h"
#include "BKE_material.h" #include "BKE_material.h"
#include "BKE_mesh.h" #include "BKE_mesh.h"
@@ -766,7 +766,11 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
size_t num_polys = new_mesh->totpoly; size_t num_polys = new_mesh->totpoly;
if (num_polys > 0) { if (num_polys > 0) {
std::map<std::string, int> mat_map; 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; return new_mesh;
@@ -775,9 +779,8 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
return existing_mesh; return existing_mesh;
} }
void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel, void AbcMeshReader::assign_facesets_to_material_indices(const ISampleSelector &sample_sel,
MPoly *mpoly, MutableSpan<int> material_indices,
int totpoly,
std::map<std::string, int> &r_mat_map) std::map<std::string, int> &r_mat_map)
{ {
std::vector<std::string> face_sets; std::vector<std::string> 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++) { for (size_t l = 0; l < num_group_faces; l++) {
size_t pos = (*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'; std::cerr << "Faceset overflow on " << faceset.getName() << '\n';
break; break;
} }
MPoly &poly = mpoly[pos]; material_indices[pos] = assigned_mat - 1;
poly.mat_nr = 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) void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const ISampleSelector &sample_sel)
{ {
std::map<std::string, int> mat_map; 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); utils::assign_materials(bmain, m_object, mat_map);
} }

View File

@@ -5,6 +5,8 @@
* \ingroup balembic * \ingroup balembic
*/ */
#include "BLI_span.hh"
#include "abc_customdata.h" #include "abc_customdata.h"
#include "abc_reader_object.h" #include "abc_reader_object.h"
@@ -38,9 +40,8 @@ class AbcMeshReader final : public AbcObjectReader {
Mesh *mesh, Mesh *mesh,
const Alembic::AbcGeom::ISampleSelector &sample_sel); const Alembic::AbcGeom::ISampleSelector &sample_sel);
void assign_facesets_to_mpoly(const Alembic::Abc::ISampleSelector &sample_sel, void assign_facesets_to_material_indices(const Alembic::Abc::ISampleSelector &sample_sel,
MPoly *mpoly, MutableSpan<int> material_indices,
int totpoly,
std::map<std::string, int> &r_mat_map); std::map<std::string, int> &r_mat_map);
}; };

View File

@@ -17,6 +17,7 @@
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "BKE_global.h" #include "BKE_global.h"
#include "BKE_lib_id.h" #include "BKE_lib_id.h"
@@ -284,15 +285,18 @@ static bool collect_vertex_counts_per_poly(Mesh *me,
int material_index, int material_index,
std::vector<unsigned long> &vcount_list) 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; MPoly *mpolys = me->mpoly;
int totpolys = me->totpoly; int totpolys = me->totpoly;
bool is_triangulated = true; bool is_triangulated = true;
int i; 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++) { for (i = 0; i < totpolys; i++) {
if (material_indices[i] == material_index) {
MPoly *p = &mpolys[i]; MPoly *p = &mpolys[i];
if (p->mat_nr == material_index) {
int vertex_count = p->totloop; int vertex_count = p->totloop;
vcount_list.push_back(vertex_count); vcount_list.push_back(vertex_count);
if (vertex_count != 3) { if (vertex_count != 3) {
@@ -397,13 +401,17 @@ void GeometryExporter::create_mesh_primitive_list(short material_index,
/* performs the actual writing */ /* performs the actual writing */
prepareToAppendValues(is_triangulated, *primitive_list, vcount_list); 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> */ /* <p> */
int texindex = 0; int texindex = 0;
for (int i = 0; i < totpolys; i++) { for (int i = 0; i < totpolys; i++) {
MPoly *p = &mpolys[i]; MPoly *p = &mpolys[i];
int loop_count = p->totloop; int loop_count = p->totloop;
if (p->mat_nr == material_index) { if (material_indices[i] == material_index) {
MLoop *l = &mloops[p->loopstart]; MLoop *l = &mloops[p->loopstart];
BCPolygonNormalsIndices normal_indices = norind[i]; BCPolygonNormalsIndices normal_indices = norind[i];

View File

@@ -615,6 +615,9 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
MaterialIdPrimitiveArrayMap mat_prim_map; 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::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives();
COLLADAFW::MeshVertexData &nor = collada_mesh->getNormals(); 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(); int collada_meshtype = mp->getPrimitiveType();
/* since we cannot set mpoly->mat_nr here, we store a portion of me->mpoly in Primitive */ /* 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 /* If MeshPrimitive is TRIANGLE_FANS we split it into triangles
* The first triangle-fan vertex will be the first vertex in every triangle * 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++; mpoly++;
if (material_indices) {
material_indices++;
}
mloop += 3; mloop += 3;
loop_index += 3; loop_index += 3;
prim.totpoly++; prim.totpoly++;
@@ -1007,10 +1013,9 @@ void MeshImporter::assign_material_to_geom(
for (it = prims.begin(); it != prims.end(); it++) { for (it = prims.begin(); it != prims.end(); it++) {
Primitive &prim = *it; Primitive &prim = *it;
MPoly *mpoly = prim.mpoly;
for (int i = 0; i < prim.totpoly; i++, mpoly++) { for (int i = 0; i < prim.totpoly; i++) {
mpoly->mat_nr = mat_index; prim.material_indices[i] = mat_index;
} }
} }
} }

View File

@@ -80,6 +80,7 @@ class MeshImporter : public MeshImporterBase {
* (<triangles>, <polylist>, etc.) */ * (<triangles>, <polylist>, etc.) */
struct Primitive { struct Primitive {
MPoly *mpoly; MPoly *mpoly;
int *material_indices;
unsigned int totpoly; unsigned int totpoly;
}; };
typedef std::map<COLLADAFW::MaterialId, std::vector<Primitive>> MaterialIdPrimitiveArrayMap; typedef std::map<COLLADAFW::MaterialId, std::vector<Primitive>> MaterialIdPrimitiveArrayMap;

View File

@@ -6,6 +6,7 @@
#include "usd_reader_mesh.h" #include "usd_reader_mesh.h"
#include "usd_reader_material.h" #include "usd_reader_material.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "BKE_main.h" #include "BKE_main.h"
#include "BKE_material.h" #include "BKE_material.h"
@@ -319,7 +320,6 @@ void USDMeshReader::read_mpolys(Mesh *mesh)
MPoly &poly = mpolys[i]; MPoly &poly = mpolys[i];
poly.loopstart = loop_index; poly.loopstart = loop_index;
poly.totloop = face_size; poly.totloop = face_size;
poly.mat_nr = 0;
/* Polygons are always assumed to be smooth-shaded. If the mesh should be flat-shaded, /* Polygons are always assumed to be smooth-shaded. If the mesh should be flat-shaded,
* this is encoded in custom loop normals. */ * this is encoded in custom loop normals. */
@@ -735,9 +735,8 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings,
} }
} }
void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime, void USDMeshReader::assign_facesets_to_material_indices(double motionSampleTime,
MPoly *mpoly, MutableSpan<int> material_indices,
const int /* totpoly */,
std::map<pxr::SdfPath, int> *r_mat_map) std::map<pxr::SdfPath, int> *r_mat_map)
{ {
if (r_mat_map == nullptr) { if (r_mat_map == nullptr) {
@@ -778,9 +777,8 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime,
pxr::VtIntArray indices; pxr::VtIntArray indices;
indicesAttribute.Get(&indices, motionSampleTime); indicesAttribute.Get(&indices, motionSampleTime);
for (int i = 0; i < indices.size(); i++) { for (const int i : indices) {
MPoly &poly = mpoly[indices[i]]; material_indices[i] = mat_idx;
poly.mat_nr = mat_idx;
} }
} }
} }
@@ -805,7 +803,12 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot
} }
std::map<pxr::SdfPath, int> mat_map; 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. */ /* Build material name map if it's not built yet. */
if (this->settings_->mat_name_to_mat.empty()) { if (this->settings_->mat_name_to_mat.empty()) {
utils::build_mat_map(bmain, &this->settings_->mat_name_to_mat); 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; size_t num_polys = active_mesh->totpoly;
if (num_polys > 0 && import_params_.import_materials) { if (num_polys > 0 && import_params_.import_materials) {
std::map<pxr::SdfPath, int> mat_map; 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();
} }
} }

View File

@@ -3,6 +3,8 @@
* Modifications Copyright 2021 Tangent Animation and. NVIDIA Corporation. All rights reserved. */ * Modifications Copyright 2021 Tangent Animation and. NVIDIA Corporation. All rights reserved. */
#pragma once #pragma once
#include "BLI_span.hh"
#include "usd.h" #include "usd.h"
#include "usd_reader_geom.h" #include "usd_reader_geom.h"
@@ -61,9 +63,8 @@ class USDMeshReader : public USDGeomReader {
/** Set USD uniform (per-face) normals as Blender loop normals. */ /** Set USD uniform (per-face) normals as Blender loop normals. */
void process_normals_uniform(Mesh *mesh); void process_normals_uniform(Mesh *mesh);
void readFaceSetsSample(Main *bmain, Mesh *mesh, double motionSampleTime); void readFaceSetsSample(Main *bmain, Mesh *mesh, double motionSampleTime);
void assign_facesets_to_mpoly(double motionSampleTime, void assign_facesets_to_material_indices(double motionSampleTime,
struct MPoly *mpoly, MutableSpan<int> material_indices,
int totpoly,
std::map<pxr::SdfPath, int> *r_mat_map); std::map<pxr::SdfPath, int> *r_mat_map);
void read_mpolys(Mesh *mesh); void read_mpolys(Mesh *mesh);

View File

@@ -11,6 +11,7 @@
#include "BLI_math_vector.h" #include "BLI_math_vector.h"
#include "BKE_attribute.h" #include "BKE_attribute.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "BKE_lib_id.h" #include "BKE_lib_id.h"
#include "BKE_material.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 /* Only construct face groups (a.k.a. geometry subsets) when we need them for material
* assignments. */ * 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_vertex_counts.reserve(mesh->totpoly);
usd_mesh_data.face_indices.reserve(mesh->totloop); 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) { for (int j = 0; j < mpoly->totloop; ++j, ++loop) {
usd_mesh_data.face_indices.push_back(loop->v); usd_mesh_data.face_indices.push_back(loop->v);
} }
if (construct_face_groups) {
usd_mesh_data.face_groups[mpoly->mat_nr].push_back(i);
}
} }
} }

View File

@@ -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. */ /* Write material name and material group if different from previous. */
if (export_params_.export_materials && obj_mesh_data.tot_materials() > 0) { 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 prev_mat = idx == 0 ? NEGATIVE_INIT : std::max(0, material_indices[prev_i]);
const int16_t mat = obj_mesh_data.ith_poly_matnr(i); const int16_t mat = std::max(0, material_indices[i]);
if (mat != prev_mat) { if (mat != prev_mat) {
if (mat == NOT_FOUND) { if (mat == NOT_FOUND) {
buf.write_obj_usemtl(MATERIAL_GROUP_DISABLED); buf.write_obj_usemtl(MATERIAL_GROUP_DISABLED);

View File

@@ -6,6 +6,7 @@
/* Silence warnings from copying deprecated fields. Needed for an Object copy constructor use. */ /* Silence warnings from copying deprecated fields. Needed for an Object copy constructor use. */
#define DNA_DEPRECATED_ALLOW #define DNA_DEPRECATED_ALLOW
#include "BKE_attribute.hh"
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "BKE_deform.h" #include "BKE_deform.h"
#include "BKE_lib_id.h" #include "BKE_lib_id.h"
@@ -199,16 +200,23 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags)
void OBJMesh::calc_poly_order() void OBJMesh::calc_poly_order()
{ {
const int tot_polys = tot_polygons(); const bke::AttributeAccessor attributes = bke::mesh_attributes(*export_mesh_eval_);
poly_order_.resize(tot_polys); const VArray<int> material_indices = attributes.lookup_or_default<int>(
for (int i = 0; i < tot_polys; ++i) { "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; poly_order_[i] = i;
} }
const MPoly *mpolys = export_mesh_eval_->mpoly;
/* Sort polygons by their material index. */ /* Sort polygons by their material index. */
blender::parallel_sort(poly_order_.begin(), poly_order_.end(), [&](int a, int b) { blender::parallel_sort(poly_order_.begin(), poly_order_.end(), [&](int a, int b) {
int mat_a = mpolys[a].mat_nr; int mat_a = material_indices_span[a];
int mat_b = mpolys[b].mat_nr; int mat_b = material_indices_span[b];
if (mat_a != mat_b) { if (mat_a != mat_b) {
return 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; 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 const char *OBJMesh::get_object_name() const
{ {
return export_object_eval_.id.name + 2; return export_object_eval_.id.name + 2;

View File

@@ -130,11 +130,6 @@ class OBJMesh : NonCopyable {
* Return mat_nr-th material of the object. The given index should be zero-based. * 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; 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_normals() const;
void ensure_mesh_edges() const; void ensure_mesh_edges() const;

View File

@@ -8,7 +8,7 @@
#include "DNA_mesh_types.h" #include "DNA_mesh_types.h"
#include "DNA_scene_types.h" #include "DNA_scene_types.h"
#include "BKE_attribute.h" #include "BKE_attribute.hh"
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "BKE_deform.h" #include "BKE_deform.h"
#include "BKE_material.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)); 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}; const int64_t tot_face_elems{mesh->totpoly};
int tot_loop_idx = 0; 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) { if (curr_face.shaded_smooth) {
mpoly.flag |= ME_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 /* Importing obj files without any materials would result in negative indices, which is not
* supported. */ * supported. */
if (mpoly.mat_nr < 0) { if (material_indices.span[poly_idx] < 0) {
mpoly.mat_nr = 0; material_indices.span[poly_idx] = 0;
} }
for (int idx = 0; idx < curr_face.corner_count_; ++idx) { 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; dw->weight = 1.0f;
} }
} }
material_indices.finish();
} }
void MeshFromGeometry::create_vertex_groups(Object *obj) void MeshFromGeometry::create_vertex_groups(Object *obj)

View File

@@ -161,7 +161,8 @@ typedef struct Mesh {
/** /**
* An array of materials, with length #totcol. These can be overridden by material slots * 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; struct Material **mat;

View File

@@ -74,7 +74,8 @@ typedef struct MPoly {
int loopstart; int loopstart;
/** Keep signed since we need to subtract when getting the previous loop. */ /** Keep signed since we need to subtract when getting the previous loop. */
int totloop; 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; char flag, _pad;
} MPoly; } MPoly;
@@ -156,8 +157,8 @@ enum {
* *
* Usage examples: * Usage examples:
* \code{.c} * \code{.c}
* // access original material. * // access polygon attribute value.
* short mat_nr = mpoly[lt->poly].mat_nr; * T value = polygon_attribute[lt->poly];
* *
* // access vertex locations. * // access vertex locations.
* float *vtri_co[3] = { * float *vtri_co[3] = {

View File

@@ -562,6 +562,22 @@ static void rna_MeshPolygon_hide_set(PointerRNA *ptr, bool value)
hide_poly[index] = 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) static void rna_MeshPolygon_center_get(PointerRNA *ptr, float *values)
{ {
Mesh *me = rna_mesh(ptr); 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) static int rna_MeshLoopTriangle_material_index_get(PointerRNA *ptr)
{ {
const Mesh *me = rna_mesh(ptr); const Mesh *me = rna_mesh(ptr);
const int *material_indices = BKE_mesh_material_indices(me);
const MLoopTri *ltri = (MLoopTri *)ptr->data; 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) 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"); 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); 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"); RNA_def_property_ui_text(prop, "Material Index", "Material slot index of this polygon");
# if 0 # if 0
RNA_def_property_int_funcs(prop, NULL, NULL, "rna_MeshPoly_material_index_range"); RNA_def_property_int_funcs(prop, NULL, NULL, "rna_MeshPoly_material_index_range");

View File

@@ -947,6 +947,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* more of an offset in this case */ /* more of an offset in this case */
edge_offset = totedge + (totvert * (step_tot - (close ? 0 : 1))); 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++) { for (i = 0; i < totedge; i++, med_new_firstloop++) {
const uint step_last = step_tot - (close ? 1 : 2); const uint step_last = step_tot - (close ? 1 : 2);
const uint mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX; 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; 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 */ /* for each edge, make a cylinder of quads */
i1 = med_new_firstloop->v1; i1 = med_new_firstloop->v1;
i2 = med_new_firstloop->v2; i2 = med_new_firstloop->v2;
if (has_mpoly_orig) { 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 { else {
mat_nr = 0; mat_nr = 0;
@@ -992,8 +995,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
} }
else { else {
origindex[mpoly_index] = ORIGINDEX_NONE; origindex[mpoly_index] = ORIGINDEX_NONE;
dst_material_index[mpoly_index] = mat_nr;
mp_new->flag = mpoly_flag; mp_new->flag = mpoly_flag;
mp_new->mat_nr = mat_nr;
} }
mp_new->loopstart = mpoly_index * 4; mp_new->loopstart = mpoly_index * 4;
mp_new->totloop = 4; mp_new->totloop = 4;

View File

@@ -425,6 +425,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
} \ } \
(void)0 (void)0
int *dst_material_index = BKE_mesh_material_indices_for_write(result);
/* flip normals */ /* flip normals */
if (do_shell) { if (do_shell) {
@@ -462,8 +464,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
#endif #endif
if (mat_ofs) { if (mat_ofs) {
mp->mat_nr += mat_ofs; dst_material_index[mp - mpoly] += mat_ofs;
CLAMP(mp->mat_nr, 0, mat_nr_max); CLAMP(dst_material_index[mp - mpoly], 0, mat_nr_max);
} }
e = ml2[0].e; 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 */ /* use the next material index if option enabled */
if (mat_ofs_rim) { if (mat_ofs_rim) {
mp->mat_nr += mat_ofs_rim; dst_material_index[mp - mpoly] += mat_ofs_rim;
CLAMP(mp->mat_nr, 0, mat_nr_max); CLAMP(dst_material_index[mp - mpoly], 0, mat_nr_max);
} }
if (crease_outer) { if (crease_outer) {
/* crease += crease_outer; without wrapping */ /* crease += crease_outer; without wrapping */

View File

@@ -2108,6 +2108,9 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
} }
#endif #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. */ /* Make boundary edges/faces. */
{ {
gs_ptr = orig_vert_groups_arr; gs_ptr = orig_vert_groups_arr;
@@ -2224,7 +2227,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
/* Loop data. */ /* Loop data. */
int *loops = MEM_malloc_arrayN(j, sizeof(*loops), "loops in solidify"); 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; short most_mat_nr = 0;
uint most_mat_nr_face = 0; uint most_mat_nr_face = 0;
uint most_mat_nr_count = 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++) { for (EdgeGroup *g3 = g2; g3->valid && k < j; g3++) {
if ((do_rim && !g3->is_orig_closed) || (do_shell && g3->split)) { if ((do_rim && !g3->is_orig_closed) || (do_shell && g3->split)) {
/* Check both far ends in terms of faces of an edge group. */ /* 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; face = g3->edges[0]->faces[0]->index;
count++; count++;
} }
NewEdgeRef *le = g3->edges[g3->edges_len - 1]; 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; face = le->faces[1]->index;
count++; 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; face = le->faces[0]->index;
count++; count++;
} }
@@ -2264,9 +2271,9 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
} }
mpoly[poly_index].loopstart = (int)loop_index; mpoly[poly_index].loopstart = (int)loop_index;
mpoly[poly_index].totloop = (int)j; mpoly[poly_index].totloop = (int)j;
mpoly[poly_index].mat_nr = most_mat_nr + dst_material_index[poly_index] = most_mat_nr +
(g->is_orig_closed || !do_rim ? 0 : mat_ofs_rim); (g->is_orig_closed || !do_rim ? 0 : mat_ofs_rim);
CLAMP(mpoly[poly_index].mat_nr, 0, mat_nr_max); CLAMP(dst_material_index[poly_index], 0, mat_nr_max);
mpoly[poly_index].flag = orig_mpoly[most_mat_nr_face].flag; mpoly[poly_index].flag = orig_mpoly[most_mat_nr_face].flag;
poly_index++; poly_index++;
@@ -2334,13 +2341,15 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
continue; 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( CustomData_copy_data(
&mesh->pdata, &result->pdata, (int)(*new_edges)->faces[0]->index, (int)poly_index, 1); &mesh->pdata, &result->pdata, (int)(*new_edges)->faces[0]->index, (int)poly_index, 1);
mpoly[poly_index].loopstart = (int)loop_index; mpoly[poly_index].loopstart = (int)loop_index;
mpoly[poly_index].totloop = 4 - (int)(v1_singularity || v2_singularity); mpoly[poly_index].totloop = 4 - (int)(v1_singularity || v2_singularity);
mpoly[poly_index].mat_nr = face->mat_nr + mat_ofs_rim; dst_material_index[poly_index] =
CLAMP(mpoly[poly_index].mat_nr, 0, mat_nr_max); (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; mpoly[poly_index].flag = face->flag;
poly_index++; 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); CustomData_copy_data(&mesh->pdata, &result->pdata, (int)(i / 2), (int)poly_index, 1);
mpoly[poly_index].loopstart = (int)loop_index; mpoly[poly_index].loopstart = (int)loop_index;
mpoly[poly_index].totloop = (int)k; mpoly[poly_index].totloop = (int)k;
mpoly[poly_index].mat_nr = fr->face->mat_nr + (fr->reversed != do_flip ? mat_ofs : 0); dst_material_index[poly_index] = (src_material_index ? src_material_index[fr->index] :
CLAMP(mpoly[poly_index].mat_nr, 0, mat_nr_max); 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; mpoly[poly_index].flag = fr->face->flag;
if (fr->reversed != do_flip) { if (fr->reversed != do_flip) {
for (int l = (int)k - 1; l >= 0; l--) { for (int l = (int)k - 1; l >= 0; l--) {

View File

@@ -23,19 +23,30 @@ static void node_declare(NodeDeclarationBuilder &b)
static void select_mesh_by_material(const Mesh &mesh, static void select_mesh_by_material(const Mesh &mesh,
const Material *material, const Material *material,
const IndexMask mask, const IndexMask mask,
const MutableSpan<bool> r_selection) MutableSpan<bool> r_selection)
{ {
BLI_assert(mesh.totpoly >= r_selection.size()); BLI_assert(mesh.totpoly >= r_selection.size());
Vector<int> material_indices; Vector<int> slots;
for (const int i : IndexRange(mesh.totcol)) { for (const int i : IndexRange(mesh.totcol)) {
if (mesh.mat[i] == material) { 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) { threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) { for (const int i : range) {
const int face_index = mask[i]; 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]);
} }
}); });
} }

View File

@@ -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); 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); MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh);
for (const int i : selection) { SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>(
MPoly &poly = mesh.mpoly[i]; "material_index", ATTR_DOMAIN_FACE);
poly.mat_nr = new_material_index; material_indices.span.fill_indices(selection, new_material_index);
} material_indices.finish();
} }
static void node_geo_exec(GeoNodeExecParams params) static void node_geo_exec(GeoNodeExecParams params)

View File

@@ -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); 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++) { for (int i = 0; i < tottri; i++) {
const MLoopTri *lt = &looptri[i]; const MLoopTri *lt = &looptri[i];
const MPoly *mp = &me->mpoly[lt->poly];
bd.primitive_id = i; bd.primitive_id = i;
/* Find images matching this material. */ /* 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++) { for (int image_id = 0; image_id < targets->images_num; image_id++) {
BakeImage *bk_image = &targets->images[image_id]; BakeImage *bk_image = &targets->images[image_id];
if (bk_image->image != image) { if (bk_image->image != image) {

View File

@@ -63,6 +63,7 @@ typedef struct {
MVert *mvert; MVert *mvert;
const float (*vert_normals)[3]; const float (*vert_normals)[3];
MPoly *mpoly; MPoly *mpoly;
const int *material_indices;
MLoop *mloop; MLoop *mloop;
MLoopUV *mloopuv; MLoopUV *mloopuv;
float uv_offset[2]; 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) { while ((tri_index = multires_bake_queue_next_tri(handle->queue)) >= 0) {
const MLoopTri *lt = &data->mlooptri[tri_index]; const MLoopTri *lt = &data->mlooptri[tri_index];
const MPoly *mp = &data->mpoly[lt->poly]; const short mat_nr = data->material_indices == NULL ? 0 : data->material_indices[lt->poly];
const short mat_nr = mp->mat_nr;
const MLoopUV *mloopuv = data->mloopuv; const MLoopUV *mloopuv = data->mloopuv;
if (multiresbake_test_break(bkr)) { if (multiresbake_test_break(bkr)) {
@@ -545,6 +545,8 @@ static void do_multires_bake(MultiresBakeRender *bkr,
handle->queue = &queue; handle->queue = &queue;
handle->data.mpoly = mpoly; 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.mvert = mvert;
handle->data.vert_normals = vert_normals; handle->data.vert_normals = vert_normals;
handle->data.mloopuv = mloopuv; handle->data.mloopuv = mloopuv;