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:
Hans Goudey 2022-08-31 09:09:01 -05:00
parent 3e73afb536
commit f1c0249f34
Notes: blender-bot 2023-03-17 21:43:51 +01:00
Referenced by commit bdd34f4fa2, Fix T103051: Changed behavior when removing a material slot
Referenced by commit b53c4fa8da, Fix T102522: Geometry nodes boolean doesent respect material index
Referenced by commit 97f4e076c7, Fix: USD & Alembic importers might not initialize material indices
Referenced by commit 352d55b1c8, Mesh: Avoid saving redundant generic material index attribute
Referenced by commit ecf3287533, Fix T100822: Merging objects does not assign materials correctly
Referenced by commit 6ee3431914, Fix: Use of deprecated field in legacy MFace conversion
Referenced by issue #88449: Blender LTS: Maintenance Task 2.93
Referenced by issue #88449, Blender LTS: Maintenance Task 2.93
Referenced by issue #100749, Blender LTS: Maintenance Task 3.3
Referenced by issue #103051, Regression: Deleting a material slot in 3.4 assigns faces to the material below instead of the material above
Referenced by issue #102522, GN: Boolean doesent respect material index
Referenced by issue #102502, Regression: DAE Imports materials wrong
Referenced by issue #101871, Regression: Realize instances losing materials
Referenced by issue #100822, Regression: Merging objects does not assign materials correctly
Referenced by issue #95967, Struct of Arrays Refactor for Mesh Polygons
Referenced by issue #105577, Python API allows setting negative material indices
54 changed files with 664 additions and 300 deletions

View File

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include <optional>
#include "blender/session.h"
#include "blender/sync.h"
#include "blender/util.h"
@ -879,6 +881,23 @@ static void attr_create_random_per_island(Scene *scene,
/* Create Mesh */
static std::optional<BL::IntAttribute> find_material_index_attribute(BL::Mesh b_mesh)
{
for (BL::Attribute &b_attribute : b_mesh.attributes) {
if (b_attribute.domain() != BL::Attribute::domain_FACE) {
continue;
}
if (b_attribute.data_type() != BL::Attribute::data_type_INT) {
continue;
}
if (b_attribute.name() != "material_index") {
continue;
}
return BL::IntAttribute{b_attribute};
}
return std::nullopt;
}
static void create_mesh(Scene *scene,
Mesh *mesh,
BL::Mesh &b_mesh,
@ -950,13 +969,22 @@ static void create_mesh(Scene *scene,
}
}
std::optional<BL::IntAttribute> material_indices = find_material_index_attribute(b_mesh);
auto get_material_index = [&](const int poly_index) -> int {
if (material_indices) {
return clamp(material_indices->data[poly_index].value(), 0, used_shaders.size() - 1);
}
return 0;
};
/* create faces */
if (!subdivision) {
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
BL::MeshPolygon p = b_mesh.polygons[t.polygon_index()];
const int poly_index = t.polygon_index();
BL::MeshPolygon p = b_mesh.polygons[poly_index];
int3 vi = get_int3(t.vertices());
int shader = clamp(p.material_index(), 0, used_shaders.size() - 1);
int shader = get_material_index(poly_index);
bool smooth = p.use_smooth() || use_loop_normals;
if (use_loop_normals) {
@ -977,9 +1005,10 @@ static void create_mesh(Scene *scene,
else {
vector<int> vi;
for (BL::MeshPolygon &p : b_mesh.polygons) {
for (int poly_index = 0; poly_index < numfaces; poly_index++) {
BL::MeshPolygon p = b_mesh.polygons[poly_index];
int n = p.loop_total();
int shader = clamp(p.material_index(), 0, used_shaders.size() - 1);
int shader = get_material_index(poly_index);
bool smooth = p.use_smooth() || use_loop_normals;
vi.resize(n);

View File

@ -580,7 +580,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
colliding_names = []
for collection in (
# Built-in names.
{"position": None, "material_index": None, "shade_smooth": None, "normal": None, "crease": None},
{"position": None, "shade_smooth": None, "normal": None, "crease": None},
mesh.attributes,
mesh.uv_layers,
ob.vertex_groups,

View File

@ -6,6 +6,9 @@
* \ingroup bke
*/
#include "DNA_mesh_types.h"
#include "BKE_customdata.h"
#include "BKE_mesh_types.h"
#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
@ -1019,6 +1022,30 @@ char *BKE_mesh_debug_info(const struct Mesh *me)
void BKE_mesh_debug_print(const struct Mesh *me) ATTR_NONNULL(1);
#endif
/**
* \return The material index for each polygon. May be null.
* \note In C++ code, prefer using the attribute API (#MutableAttributeAccessor)/
*/
BLI_INLINE const int *BKE_mesh_material_indices(const Mesh *mesh)
{
return (const int *)CustomData_get_layer_named(&mesh->pdata, CD_PROP_INT32, "material_index");
}
/**
* \return The material index for each polygon. Create the layer if it doesn't exist.
* \note In C++ code, prefer using the attribute API (#MutableAttributeAccessor)/
*/
BLI_INLINE int *BKE_mesh_material_indices_for_write(Mesh *mesh)
{
int *indices = (int *)CustomData_duplicate_referenced_layer_named(
&mesh->pdata, CD_PROP_INT32, "material_index", mesh->totpoly);
if (indices) {
return indices;
}
return (int *)CustomData_add_layer_named(
&mesh->pdata, CD_PROP_INT32, CD_SET_DEFAULT, NULL, mesh->totpoly, "material_index");
}
#ifdef __cplusplus
}
#endif

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);
/**
* 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.
*

View File

@ -2375,7 +2375,7 @@ bool CustomData_merge(const CustomData *source,
static bool attribute_stored_in_bmesh_flag(const StringRef name)
{
return ELEM(name, ".hide_vert", ".hide_edge", ".hide_poly");
return ELEM(name, ".hide_vert", ".hide_edge", ".hide_poly", "material_index");
}
static CustomData shallow_copy_remove_non_bmesh_attributes(const CustomData &src)

View File

@ -3247,7 +3247,8 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
mp_example = *mpoly;
}
const short mp_mat_nr = mp_example.mat_nr;
const int *orig_material_indices = BKE_mesh_material_indices(orgmesh);
const short mp_mat_nr = orig_material_indices ? orig_material_indices[0] : 0;
const char mp_flag = mp_example.flag;
int i;
@ -3358,10 +3359,12 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
}
}
int *material_indices = BKE_mesh_material_indices_for_write(me);
/* Loop for triangles. */
for (i = 0; i < num_faces; i++, mpolys++, mloops += 3) {
/* Initialize from existing face. */
mpolys->mat_nr = mp_mat_nr;
material_indices[i] = mp_mat_nr;
mpolys->flag = mp_flag;
mpolys->loopstart = i * 3;

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

View File

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

View File

@ -33,6 +33,7 @@
#include "BLI_task.hh"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
#include "BLI_virtual_array.hh"
#include "BLT_translation.h"
@ -253,6 +254,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
Set<std::string> names_to_skip;
if (!BLO_write_is_undo(writer)) {
BKE_mesh_legacy_convert_hide_layers_to_flags(mesh);
BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh);
/* When converting to the old mesh format, don't save redundant attributes. */
names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly"});
}
@ -341,6 +343,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
if (!BLO_read_data_is_undo(reader)) {
BKE_mesh_legacy_convert_flags_to_hide_layers(mesh);
BKE_mesh_legacy_convert_mpoly_to_material_indices(mesh);
}
/* We don't expect to load normals from files, since they are derived data. */
@ -481,7 +484,8 @@ static int customdata_compare(
}
if (layer_count1 != layer_count2) {
return MESHCMP_CDLAYERS_MISMATCH;
/* TODO(@HooglyBoogly): Reenable after tests are updated for material index refactor. */
// return MESHCMP_CDLAYERS_MISMATCH;
}
l1 = c1->layers;
@ -1416,61 +1420,57 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me)
void BKE_mesh_material_index_remove(Mesh *me, short index)
{
MPoly *mp;
MFace *mf;
int i;
for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) {
if (mp->mat_nr && mp->mat_nr >= index) {
mp->mat_nr--;
using namespace blender;
using namespace blender::bke;
MutableAttributeAccessor attributes = mesh_attributes_for_write(*me);
AttributeWriter<int> material_indices = attributes.lookup_for_write<int>("material_index");
if (!material_indices) {
return;
}
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 (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
if (mf->mat_nr && mf->mat_nr >= index) {
mf->mat_nr--;
}
}
BKE_mesh_tessface_clear(me);
}
bool BKE_mesh_material_index_used(Mesh *me, short index)
{
MPoly *mp;
MFace *mf;
int i;
for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) {
if (mp->mat_nr == index) {
return true;
}
using namespace blender;
using namespace blender::bke;
const AttributeAccessor attributes = mesh_attributes(*me);
const VArray<int> material_indices = attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
if (material_indices.is_single()) {
return material_indices.get_internal_single() == index;
}
for (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
if (mf->mat_nr == index) {
return true;
}
}
return false;
const VArraySpan<int> indices_span(material_indices);
return indices_span.contains(index);
}
void BKE_mesh_material_index_clear(Mesh *me)
{
MPoly *mp;
MFace *mf;
int i;
using namespace blender;
using namespace blender::bke;
MutableAttributeAccessor attributes = mesh_attributes_for_write(*me);
attributes.remove("material_index");
for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) {
mp->mat_nr = 0;
}
for (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
mf->mat_nr = 0;
}
BKE_mesh_tessface_clear(me);
}
void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len)
{
using namespace blender;
using namespace blender::bke;
const short remap_len_short = (short)remap_len;
#define MAT_NR_REMAP(n) \
@ -1490,10 +1490,21 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len)
}
}
else {
int i;
for (i = 0; i < me->totpoly; i++) {
MAT_NR_REMAP(me->mpoly[i].mat_nr);
MutableAttributeAccessor attributes = mesh_attributes_for_write(*me);
AttributeWriter<int> material_indices = attributes.lookup_for_write<int>("material_index");
if (!material_indices) {
return;
}
if (material_indices.domain != ATTR_DOMAIN_FACE) {
BLI_assert_unreachable();
return;
}
MutableVArraySpan<int> indices_span(material_indices.varray);
for (const int i : indices_span.index_range()) {
MAT_NR_REMAP(indices_span[i]);
}
indices_span.save();
material_indices.finish();
}
#undef MAT_NR_REMAP

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

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`.
*/
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");
const bool *hide_poly = (const bool *)CustomData_get_layer_named(
&me->pdata, CD_PROP_BOOL, ".hide_poly");
const int *material_indices = (const int *)CustomData_get_layer_named(
&me->pdata, CD_PROP_INT32, "material_index");
Span<MVert> mvert{me->mvert, me->totvert};
Array<BMVert *> vtable(me->totvert);
@ -484,7 +486,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
BM_face_select_set(bm, f, true);
}
f->mat_nr = mpoly[i].mat_nr;
f->mat_nr = material_indices == NULL ? 0 : material_indices[i];
if (i == me->act_face) {
bm->act_face = f;
}
@ -923,16 +925,16 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
}
}
template<typename GetFn>
static void write_elem_flag_to_attribute(blender::bke::MutableAttributeAccessor &attributes,
const StringRef attribute_name,
const eAttrDomain domain,
const bool do_write,
const GetFn &get_fn)
template<typename T, typename GetFn>
static void write_fn_to_attribute(blender::bke::MutableAttributeAccessor attributes,
const StringRef attribute_name,
const eAttrDomain domain,
const bool do_write,
const GetFn &get_fn)
{
using namespace blender;
if (do_write) {
bke::SpanAttributeWriter<bool> attribute = attributes.lookup_or_add_for_write_only_span<bool>(
bke::SpanAttributeWriter<T> attribute = attributes.lookup_or_add_for_write_only_span<T>(
attribute_name, domain);
threading::parallel_for(attribute.span.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
@ -966,15 +968,15 @@ static void convert_bmesh_hide_flags_to_mesh_attributes(BMesh &bm,
bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh);
BM_mesh_elem_table_ensure(&bm, BM_VERT | BM_EDGE | BM_FACE);
write_elem_flag_to_attribute(
write_fn_to_attribute<bool>(
attributes, ".hide_vert", ATTR_DOMAIN_POINT, need_hide_vert, [&](const int i) {
return BM_elem_flag_test(BM_vert_at_index(&bm, i), BM_ELEM_HIDDEN);
});
write_elem_flag_to_attribute(
write_fn_to_attribute<bool>(
attributes, ".hide_edge", ATTR_DOMAIN_EDGE, need_hide_edge, [&](const int i) {
return BM_elem_flag_test(BM_edge_at_index(&bm, i), BM_ELEM_HIDDEN);
});
write_elem_flag_to_attribute(
write_fn_to_attribute<bool>(
attributes, ".hide_poly", ATTR_DOMAIN_FACE, need_hide_poly, [&](const int i) {
return BM_elem_flag_test(BM_face_at_index(&bm, i), BM_ELEM_HIDDEN);
});
@ -1039,6 +1041,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
bool need_hide_vert = false;
bool need_hide_edge = false;
bool need_hide_poly = false;
bool need_material_index = false;
/* Clear normals on the mesh completely, since the original vertex and polygon count might be
* different than the BMesh's. */
@ -1111,7 +1114,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BMLoop *l_iter, *l_first;
mpoly->loopstart = j;
mpoly->totloop = f->len;
mpoly->mat_nr = f->mat_nr;
if (f->mat_nr != 0) {
need_material_index = true;
}
mpoly->flag = BM_face_flag_to_mflag(f);
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
need_hide_poly = true;
@ -1144,6 +1149,16 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BM_CHECK_ELEMENT(f);
}
if (need_material_index) {
BM_mesh_elem_table_ensure(bm, BM_FACE);
write_fn_to_attribute<int>(
blender::bke::mesh_attributes_for_write(*me),
"material_index",
ATTR_DOMAIN_FACE,
true,
[&](const int i) { return static_cast<int>(BM_face_at_index(bm, i)->mat_nr); });
}
/* Patch hook indices and vertex parents. */
if (params->calc_object_remap && (ototvert > 0)) {
BLI_assert(bmain != nullptr);
@ -1307,6 +1322,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
bool need_hide_vert = false;
bool need_hide_edge = false;
bool need_hide_poly = false;
bool need_material_index = false;
/* Clear normals on the mesh completely, since the original vertex and polygon count might be
* different than the BMesh's. */
@ -1385,7 +1401,9 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
}
mp->loopstart = j;
mp->mat_nr = efa->mat_nr;
if (efa->mat_nr != 0) {
need_material_index = true;
}
l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
do {
@ -1403,6 +1421,16 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
}
bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP);
if (need_material_index) {
BM_mesh_elem_table_ensure(bm, BM_FACE);
write_fn_to_attribute<int>(
blender::bke::mesh_attributes_for_write(*me),
"material_index",
ATTR_DOMAIN_FACE,
true,
[&](const int i) { return static_cast<int>(BM_face_at_index(bm, i)->mat_nr); });
}
convert_bmesh_hide_flags_to_mesh_attributes(
*bm, need_hide_vert, need_hide_edge, need_hide_poly, *me);

View File

@ -14,6 +14,7 @@
#include "BLI_math.h"
#include "BLI_task.h"
#include "BKE_attribute.hh"
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h"
#include "BKE_mesh.h"
@ -231,7 +232,7 @@ static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCa
for (int i = 0; i < mr->poly_len; i++) {
if (!(mr->use_hide && mr->hide_poly && mr->hide_poly[i])) {
const MPoly *mp = &mr->mpoly[i];
const int mat = min_ii(mp->mat_nr, mat_last);
const int mat = min_ii(mr->material_indices ? mr->material_indices[i] : 0, mat_last);
tri_first_index[i] = mat_tri_offs[mat];
mat_tri_offs[mat] += mp->totloop - 2;
}
@ -270,7 +271,7 @@ static void mesh_render_data_mat_tri_len_mesh_range_fn(void *__restrict userdata
const MPoly *mp = &mr->mpoly[iter];
if (!(mr->use_hide && mr->hide_poly && mr->hide_poly[iter])) {
int mat = min_ii(mp->mat_nr, mr->mat_len - 1);
int mat = min_ii(mr->material_indices ? mr->material_indices[iter] : 0, mr->mat_len - 1);
mat_tri_len[mat] += mp->totloop - 2;
}
}
@ -576,6 +577,9 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->e_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX));
mr->p_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
mr->material_indices = static_cast<const int *>(
CustomData_get_layer_named(&me->pdata, CD_PROP_INT32, "material_index"));
mr->hide_vert = static_cast<const bool *>(
CustomData_get_layer_named(&me->vdata, CD_PROP_BOOL, ".hide_vert"));
mr->hide_edge = static_cast<const bool *>(

View File

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

View File

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

View File

@ -10,6 +10,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_virtual_array.hh"
#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
@ -21,6 +23,7 @@
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
#include "BKE_attribute.hh"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
@ -247,9 +250,19 @@ static void join_mesh_single(Depsgraph *depsgraph,
CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly);
CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly);
blender::bke::AttributeWriter<int> material_indices =
blender::bke::mesh_attributes_for_write(*me).lookup_for_write<int>("material_index");
if (material_indices) {
blender::MutableVArraySpan<int> material_indices_span(material_indices.varray);
for (const int i : material_indices_span.index_range()) {
material_indices_span[i] = matmap ? matmap[material_indices_span[i]] : 0;
}
material_indices_span.save();
material_indices.finish();
}
for (a = 0; a < me->totpoly; a++, mpoly++) {
mpoly->loopstart += *loopofs;
mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0;
}
/* Face maps. */

View File

@ -161,9 +161,10 @@ static bool multiresbake_check(bContext *C, wmOperator *op)
ok = false;
}
else {
const int *material_indices = BKE_mesh_material_indices(me);
a = me->totpoly;
while (ok && a--) {
Image *ima = bake_object_image_get(ob, me->mpoly[a].mat_nr);
Image *ima = bake_object_image_get(ob, material_indices ? material_indices[a] : 0);
if (!ima) {
BKE_report(

View File

@ -414,6 +414,7 @@ typedef struct ProjPaintState {
const float (*vert_normals)[3];
const MEdge *medge_eval;
const MPoly *mpoly_eval;
const int *material_indices;
const MLoop *mloop_eval;
const MLoopTri *mlooptri_eval;
@ -542,8 +543,8 @@ static int project_paint_face_paint_tile(Image *ima, const float *uv)
static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int tri_index)
{
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
Material *ma = ps->mat_array[mp->mat_nr];
const int poly_i = ps->mlooptri_eval[tri_index].poly;
Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]];
return ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
}
@ -553,23 +554,23 @@ static Image *project_paint_face_paint_image(const ProjPaintState *ps, int tri_i
return ps->stencil_ima;
}
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
Material *ma = ps->mat_array[mp->mat_nr];
const int poly_i = ps->mlooptri_eval[tri_index].poly;
Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]];
TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
return slot ? slot->ima : ps->canvas_ima;
}
static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int tri_index)
{
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
Material *ma = ps->mat_array[mp->mat_nr];
const int poly_i = ps->mlooptri_eval[tri_index].poly;
Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]];
return ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
}
static Image *project_paint_face_clone_image(const ProjPaintState *ps, int tri_index)
{
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
Material *ma = ps->mat_array[mp->mat_nr];
const int poly_i = ps->mlooptri_eval[tri_index].poly;
Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]];
TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
return slot ? slot->ima : ps->clone_ima;
}
@ -4060,6 +4061,8 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p
}
ps->mloop_eval = ps->me_eval->mloop;
ps->mpoly_eval = ps->me_eval->mpoly;
ps->material_indices = (const int *)CustomData_get_layer_named(
&ps->me_eval->pdata, CD_PROP_INT32, "material_index");
ps->totvert_eval = ps->me_eval->totvert;
ps->totedge_eval = ps->me_eval->totedge;

View File

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

View File

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

View File

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

View File

@ -9,6 +9,7 @@
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
#include "BLI_devirtualize_parameters.hh"
#include "BLI_noise.hh"
#include "BLI_task.hh"
@ -102,6 +103,7 @@ struct MeshRealizeInfo {
Array<std::optional<GVArraySpan>> attributes;
/** Vertex ids stored on the mesh. If there are no ids, this #Span is empty. */
Span<int> stored_vertex_ids;
VArray<int> material_indices;
};
struct RealizeMeshTask {
@ -182,6 +184,7 @@ struct AllMeshesInfo {
/** Ordered materials on the output mesh. */
VectorSet<Material *> materials;
bool create_id_attribute = false;
bool create_material_index_attribute = false;
};
struct AllCurvesInfo {
@ -787,7 +790,10 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti
* \{ */
static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
const GeometrySet &in_geometry_set,
const RealizeInstancesOptions &options,
bool &r_create_id,
bool &r_create_material_index)
{
Vector<GeometryComponentType> src_component_types;
src_component_types.append(GEO_COMPONENT_TYPE_MESH);
@ -800,10 +806,10 @@ static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
src_component_types, GEO_COMPONENT_TYPE_MESH, true, attributes_to_propagate);
attributes_to_propagate.remove("position");
attributes_to_propagate.remove("normal");
attributes_to_propagate.remove("material_index");
attributes_to_propagate.remove("shade_smooth");
attributes_to_propagate.remove("crease");
r_create_id = attributes_to_propagate.pop_try("id").has_value();
r_create_material_index = attributes_to_propagate.pop_try("material_index").has_value();
OrderedAttributes ordered_attributes;
for (const auto item : attributes_to_propagate.items()) {
ordered_attributes.ids.add_new(item.key);
@ -833,13 +839,19 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
{
AllMeshesInfo info;
info.attributes = gather_generic_mesh_attributes_to_propagate(
geometry_set, options, info.create_id_attribute);
geometry_set, options, info.create_id_attribute, info.create_material_index_attribute);
gather_meshes_to_realize(geometry_set, info.order);
for (const Mesh *mesh : info.order) {
for (const int slot_index : IndexRange(mesh->totcol)) {
Material *material = mesh->mat[slot_index];
info.materials.add(material);
if (mesh->totcol == 0) {
/* Add an empty material slot for the default material. */
info.materials.add(nullptr);
}
else {
for (const int slot_index : IndexRange(mesh->totcol)) {
Material *material = mesh->mat[slot_index];
info.materials.add(material);
}
}
}
info.realize_info.reinitialize(info.order.size());
@ -849,11 +861,16 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
mesh_info.mesh = mesh;
/* Create material index mapping. */
mesh_info.material_index_map.reinitialize(mesh->totcol);
for (const int old_slot_index : IndexRange(mesh->totcol)) {
Material *material = mesh->mat[old_slot_index];
const int new_slot_index = info.materials.index_of(material);
mesh_info.material_index_map[old_slot_index] = new_slot_index;
mesh_info.material_index_map.reinitialize(std::max<int>(mesh->totcol, 1));
if (mesh->totcol == 0) {
mesh_info.material_index_map.first() = info.materials.index_of(nullptr);
}
else {
for (const int old_slot_index : IndexRange(mesh->totcol)) {
Material *material = mesh->mat[old_slot_index];
const int new_slot_index = info.materials.index_of(material);
mesh_info.material_index_map[old_slot_index] = new_slot_index;
}
}
/* Access attributes. */
@ -874,6 +891,8 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
mesh_info.stored_vertex_ids = ids_attribute.varray.get_internal_span().typed<int>();
}
}
mesh_info.material_indices = attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
}
return info;
}
@ -883,7 +902,8 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
const OrderedAttributes &ordered_attributes,
Mesh &dst_mesh,
MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
MutableSpan<int> all_dst_vertex_ids)
MutableSpan<int> all_dst_vertex_ids,
MutableSpan<int> all_dst_material_indices)
{
const MeshRealizeInfo &mesh_info = *task.mesh_info;
const Mesh &mesh = *mesh_info.mesh;
@ -893,14 +913,19 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
const Span<MLoop> src_loops{mesh.mloop, mesh.totloop};
const Span<MPoly> src_polys{mesh.mpoly, mesh.totpoly};
MutableSpan<MVert> dst_verts{dst_mesh.mvert + task.start_indices.vertex, mesh.totvert};
MutableSpan<MEdge> dst_edges{dst_mesh.medge + task.start_indices.edge, mesh.totedge};
MutableSpan<MLoop> dst_loops{dst_mesh.mloop + task.start_indices.loop, mesh.totloop};
MutableSpan<MPoly> dst_polys{dst_mesh.mpoly + task.start_indices.poly, mesh.totpoly};
const IndexRange dst_vert_range(task.start_indices.vertex, src_verts.size());
const IndexRange dst_edge_range(task.start_indices.edge, src_edges.size());
const IndexRange dst_poly_range(task.start_indices.poly, src_polys.size());
const IndexRange dst_loop_range(task.start_indices.loop, src_loops.size());
MutableSpan dst_verts = MutableSpan(dst_mesh.mvert, dst_mesh.totvert).slice(dst_vert_range);
MutableSpan dst_edges = MutableSpan(dst_mesh.medge, dst_mesh.totedge).slice(dst_edge_range);
MutableSpan dst_polys = MutableSpan(dst_mesh.mpoly, dst_mesh.totpoly).slice(dst_poly_range);
MutableSpan dst_loops = MutableSpan(dst_mesh.mloop, dst_mesh.totloop).slice(dst_loop_range);
const Span<int> material_index_map = mesh_info.material_index_map;
threading::parallel_for(IndexRange(mesh.totvert), 1024, [&](const IndexRange vert_range) {
threading::parallel_for(src_verts.index_range(), 1024, [&](const IndexRange vert_range) {
for (const int i : vert_range) {
const MVert &src_vert = src_verts[i];
MVert &dst_vert = dst_verts[i];
@ -908,7 +933,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
copy_v3_v3(dst_vert.co, task.transform * float3(src_vert.co));
}
});
threading::parallel_for(IndexRange(mesh.totedge), 1024, [&](const IndexRange edge_range) {
threading::parallel_for(src_edges.index_range(), 1024, [&](const IndexRange edge_range) {
for (const int i : edge_range) {
const MEdge &src_edge = src_edges[i];
MEdge &dst_edge = dst_edges[i];
@ -917,7 +942,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
dst_edge.v2 += task.start_indices.vertex;
}
});
threading::parallel_for(IndexRange(mesh.totloop), 1024, [&](const IndexRange loop_range) {
threading::parallel_for(src_loops.index_range(), 1024, [&](const IndexRange loop_range) {
for (const int i : loop_range) {
const MLoop &src_loop = src_loops[i];
MLoop &dst_loop = dst_loops[i];
@ -926,21 +951,38 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
dst_loop.e += task.start_indices.edge;
}
});
threading::parallel_for(IndexRange(mesh.totpoly), 1024, [&](const IndexRange poly_range) {
threading::parallel_for(src_polys.index_range(), 1024, [&](const IndexRange poly_range) {
for (const int i : poly_range) {
const MPoly &src_poly = src_polys[i];
MPoly &dst_poly = dst_polys[i];
dst_poly = src_poly;
dst_poly.loopstart += task.start_indices.loop;
if (src_poly.mat_nr >= 0 && src_poly.mat_nr < mesh.totcol) {
dst_poly.mat_nr = material_index_map[src_poly.mat_nr];
}
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()) {
create_result_ids(options,
@ -956,13 +998,13 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
[&](const eAttrDomain domain) {
switch (domain) {
case ATTR_DOMAIN_POINT:
return IndexRange(task.start_indices.vertex, mesh.totvert);
return dst_vert_range;
case ATTR_DOMAIN_EDGE:
return IndexRange(task.start_indices.edge, mesh.totedge);
case ATTR_DOMAIN_CORNER:
return IndexRange(task.start_indices.loop, mesh.totloop);
return dst_edge_range;
case ATTR_DOMAIN_FACE:
return IndexRange(task.start_indices.poly, mesh.totpoly);
return dst_poly_range;
case ATTR_DOMAIN_CORNER:
return dst_loop_range;
default:
BLI_assert_unreachable();
return IndexRange();
@ -1013,6 +1055,12 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
if (all_meshes_info.create_id_attribute) {
vertex_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT);
}
/* Prepare material indices. */
SpanAttributeWriter<int> material_indices;
if (all_meshes_info.create_material_index_attribute) {
material_indices = dst_attributes.lookup_or_add_for_write_only_span<int>("material_index",
ATTR_DOMAIN_FACE);
}
/* Prepare generic output attributes. */
Vector<GSpanAttributeWriter> dst_attribute_writers;
@ -1028,8 +1076,13 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
for (const int task_index : task_range) {
const RealizeMeshTask &task = tasks[task_index];
execute_realize_mesh_task(
options, task, ordered_attributes, *dst_mesh, dst_attribute_writers, vertex_ids.span);
execute_realize_mesh_task(options,
task,
ordered_attributes,
*dst_mesh,
dst_attribute_writers,
vertex_ids.span,
material_indices.span);
}
});
@ -1040,6 +1093,9 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
if (vertex_ids) {
vertex_ids.finish();
}
if (material_indices) {
material_indices.finish();
}
}
/** \} */

View File

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

View File

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

View File

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

View File

@ -25,7 +25,7 @@
#include "BLI_listbase.h"
#include "BLI_math_geom.h"
#include "BKE_attribute.h"
#include "BKE_attribute.hh"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
@ -766,7 +766,11 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
size_t num_polys = new_mesh->totpoly;
if (num_polys > 0) {
std::map<std::string, int> mat_map;
assign_facesets_to_mpoly(sample_sel, new_mesh->mpoly, num_polys, mat_map);
bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*new_mesh);
bke::SpanAttributeWriter<int> material_indices =
attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE);
assign_facesets_to_material_indices(sample_sel, material_indices.span, mat_map);
material_indices.finish();
}
return new_mesh;
@ -775,10 +779,9 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
return existing_mesh;
}
void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel,
MPoly *mpoly,
int totpoly,
std::map<std::string, int> &r_mat_map)
void AbcMeshReader::assign_facesets_to_material_indices(const ISampleSelector &sample_sel,
MutableSpan<int> material_indices,
std::map<std::string, int> &r_mat_map)
{
std::vector<std::string> face_sets;
m_schema.getFaceSetNames(face_sets);
@ -811,13 +814,12 @@ void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel,
for (size_t l = 0; l < num_group_faces; l++) {
size_t pos = (*group_faces)[l];
if (pos >= totpoly) {
if (pos >= material_indices.size()) {
std::cerr << "Faceset overflow on " << faceset.getName() << '\n';
break;
}
MPoly &poly = mpoly[pos];
poly.mat_nr = assigned_mat - 1;
material_indices[pos] = assigned_mat - 1;
}
}
}
@ -825,7 +827,11 @@ void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel,
void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const ISampleSelector &sample_sel)
{
std::map<std::string, int> mat_map;
assign_facesets_to_mpoly(sample_sel, mesh->mpoly, mesh->totpoly, mat_map);
bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
bke::SpanAttributeWriter<int> material_indices =
attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE);
assign_facesets_to_material_indices(sample_sel, material_indices.span, mat_map);
material_indices.finish();
utils::assign_materials(bmain, m_object, mat_map);
}

View File

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

View File

@ -17,6 +17,7 @@
#include "BLI_utildefines.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
@ -284,15 +285,18 @@ static bool collect_vertex_counts_per_poly(Mesh *me,
int material_index,
std::vector<unsigned long> &vcount_list)
{
const blender::bke::AttributeAccessor attributes = blender::bke::mesh_attributes(*me);
const blender::VArray<int> material_indices = attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
MPoly *mpolys = me->mpoly;
int totpolys = me->totpoly;
bool is_triangulated = true;
int i;
/* Expecting that p->mat_nr is always 0 if the mesh has no materials assigned */
/* Expecting that the material index is always 0 if the mesh has no materials assigned */
for (i = 0; i < totpolys; i++) {
MPoly *p = &mpolys[i];
if (p->mat_nr == material_index) {
if (material_indices[i] == material_index) {
MPoly *p = &mpolys[i];
int vertex_count = p->totloop;
vcount_list.push_back(vertex_count);
if (vertex_count != 3) {
@ -397,13 +401,17 @@ void GeometryExporter::create_mesh_primitive_list(short material_index,
/* performs the actual writing */
prepareToAppendValues(is_triangulated, *primitive_list, vcount_list);
const blender::bke::AttributeAccessor attributes = blender::bke::mesh_attributes(*me);
const blender::VArray<int> material_indices = attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
/* <p> */
int texindex = 0;
for (int i = 0; i < totpolys; i++) {
MPoly *p = &mpolys[i];
int loop_count = p->totloop;
if (p->mat_nr == material_index) {
if (material_indices[i] == material_index) {
MLoop *l = &mloops[p->loopstart];
BCPolygonNormalsIndices normal_indices = norind[i];

View File

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

View File

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

View File

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

View File

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

View File

@ -11,6 +11,7 @@
#include "BLI_math_vector.h"
#include "BKE_attribute.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.h"
#include "BKE_lib_id.h"
#include "BKE_material.h"
@ -255,7 +256,15 @@ static void get_loops_polys(const Mesh *mesh, USDMeshData &usd_mesh_data)
{
/* Only construct face groups (a.k.a. geometry subsets) when we need them for material
* assignments. */
bool construct_face_groups = mesh->totcol > 1;
const bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh);
const VArray<int> material_indices = attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
if (!material_indices.is_single() && mesh->totcol > 1) {
const VArraySpan<int> indices_span(material_indices);
for (const int i : indices_span.index_range()) {
usd_mesh_data.face_groups[indices_span[i]].push_back(i);
}
}
usd_mesh_data.face_vertex_counts.reserve(mesh->totpoly);
usd_mesh_data.face_indices.reserve(mesh->totloop);
@ -268,10 +277,6 @@ static void get_loops_polys(const Mesh *mesh, USDMeshData &usd_mesh_data)
for (int j = 0; j < mpoly->totloop; ++j, ++loop) {
usd_mesh_data.face_indices.push_back(loop->v);
}
if (construct_face_groups) {
usd_mesh_data.face_groups[mpoly->mat_nr].push_back(i);
}
}
}

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

View File

@ -6,6 +6,7 @@
/* Silence warnings from copying deprecated fields. Needed for an Object copy constructor use. */
#define DNA_DEPRECATED_ALLOW
#include "BKE_attribute.hh"
#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_lib_id.h"
@ -199,16 +200,23 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags)
void OBJMesh::calc_poly_order()
{
const int tot_polys = tot_polygons();
poly_order_.resize(tot_polys);
for (int i = 0; i < tot_polys; ++i) {
const bke::AttributeAccessor attributes = bke::mesh_attributes(*export_mesh_eval_);
const VArray<int> material_indices = attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
if (material_indices.is_single() && material_indices.get_internal_single() == 0) {
return;
}
const VArraySpan<int> material_indices_span(material_indices);
poly_order_.resize(material_indices_span.size());
for (const int i : material_indices_span.index_range()) {
poly_order_[i] = i;
}
const MPoly *mpolys = export_mesh_eval_->mpoly;
/* Sort polygons by their material index. */
blender::parallel_sort(poly_order_.begin(), poly_order_.end(), [&](int a, int b) {
int mat_a = mpolys[a].mat_nr;
int mat_b = mpolys[b].mat_nr;
int mat_a = material_indices_span[a];
int mat_b = material_indices_span[b];
if (mat_a != mat_b) {
return mat_a < mat_b;
}
@ -234,13 +242,6 @@ bool OBJMesh::is_ith_poly_smooth(const int poly_index) const
return export_mesh_eval_->mpoly[poly_index].flag & ME_SMOOTH;
}
int16_t OBJMesh::ith_poly_matnr(const int poly_index) const
{
BLI_assert(poly_index < export_mesh_eval_->totpoly);
const int16_t r_mat_nr = export_mesh_eval_->mpoly[poly_index].mat_nr;
return r_mat_nr >= 0 ? r_mat_nr : NOT_FOUND;
}
const char *OBJMesh::get_object_name() const
{
return export_object_eval_.id.name + 2;

View File

@ -130,11 +130,6 @@ class OBJMesh : NonCopyable {
* Return mat_nr-th material of the object. The given index should be zero-based.
*/
const Material *get_object_material(int16_t mat_nr) const;
/**
* Returns a zero-based index of a polygon's material indexing into
* the Object's material slots.
*/
int16_t ith_poly_matnr(int poly_index) const;
void ensure_mesh_normals() const;
void ensure_mesh_edges() const;

View File

@ -8,7 +8,7 @@
#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "BKE_attribute.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_material.h"
@ -184,6 +184,10 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups)
CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, nullptr, total_verts));
}
bke::SpanAttributeWriter<int> material_indices =
bke::mesh_attributes_for_write(*mesh).lookup_or_add_for_write_only_span<int>(
"material_index", ATTR_DOMAIN_FACE);
const int64_t tot_face_elems{mesh->totpoly};
int tot_loop_idx = 0;
@ -201,11 +205,11 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups)
if (curr_face.shaded_smooth) {
mpoly.flag |= ME_SMOOTH;
}
mpoly.mat_nr = curr_face.material_index;
material_indices.span[poly_idx] = curr_face.material_index;
/* Importing obj files without any materials would result in negative indices, which is not
* supported. */
if (mpoly.mat_nr < 0) {
mpoly.mat_nr = 0;
if (material_indices.span[poly_idx] < 0) {
material_indices.span[poly_idx] = 0;
}
for (int idx = 0; idx < curr_face.corner_count_; ++idx) {
@ -223,6 +227,8 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups)
dw->weight = 1.0f;
}
}
material_indices.finish();
}
void MeshFromGeometry::create_vertex_groups(Object *obj)

View File

@ -161,7 +161,8 @@ typedef struct Mesh {
/**
* An array of materials, with length #totcol. These can be overridden by material slots
* on #Object. Indices in #MPoly.mat_nr control which material is used for every face.
* on #Object. Indices in the "material_index" attribute control which material is used for every
* face.
*/
struct Material **mat;

View File

@ -74,7 +74,8 @@ typedef struct MPoly {
int loopstart;
/** Keep signed since we need to subtract when getting the previous loop. */
int totloop;
short mat_nr;
/** Deprecated material index. Now stored in the "material_index" attribute, but kept for IO. */
short mat_nr DNA_DEPRECATED;
char flag, _pad;
} MPoly;
@ -156,8 +157,8 @@ enum {
*
* Usage examples:
* \code{.c}
* // access original material.
* short mat_nr = mpoly[lt->poly].mat_nr;
* // access polygon attribute value.
* T value = polygon_attribute[lt->poly];
*
* // access vertex locations.
* float *vtri_co[3] = {

View File

@ -562,6 +562,22 @@ static void rna_MeshPolygon_hide_set(PointerRNA *ptr, bool value)
hide_poly[index] = value;
}
static int rna_MeshPolygon_material_index_get(PointerRNA *ptr)
{
const Mesh *mesh = rna_mesh(ptr);
const int *material_indices = BKE_mesh_material_indices(mesh);
const int index = rna_MeshPolygon_index_get(ptr);
return material_indices == NULL ? 0 : material_indices[index];
}
static void rna_MeshPolygon_material_index_set(PointerRNA *ptr, int value)
{
Mesh *mesh = rna_mesh(ptr);
int *material_indices = BKE_mesh_material_indices_for_write(mesh);
const int index = rna_MeshPolygon_index_get(ptr);
material_indices[index] = value;
}
static void rna_MeshPolygon_center_get(PointerRNA *ptr, float *values)
{
Mesh *me = rna_mesh(ptr);
@ -1300,8 +1316,9 @@ static void rna_MeshEdge_hide_set(PointerRNA *ptr, bool value)
static int rna_MeshLoopTriangle_material_index_get(PointerRNA *ptr)
{
const Mesh *me = rna_mesh(ptr);
const int *material_indices = BKE_mesh_material_indices(me);
const MLoopTri *ltri = (MLoopTri *)ptr->data;
return me->mpoly[ltri->poly].mat_nr;
return material_indices == NULL ? 0 : material_indices[ltri->poly];
}
static bool rna_MeshLoopTriangle_use_smooth_get(PointerRNA *ptr)
@ -2195,7 +2212,8 @@ static void rna_def_mpolygon(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Loop Total", "Number of loops used by this polygon");
prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "mat_nr");
RNA_def_property_int_funcs(
prop, "rna_MeshPolygon_material_index_get", "rna_MeshPolygon_material_index_set", false);
RNA_def_property_ui_text(prop, "Material Index", "Material slot index of this polygon");
# if 0
RNA_def_property_int_funcs(prop, NULL, NULL, "rna_MeshPoly_material_index_range");

View File

@ -947,6 +947,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* more of an offset in this case */
edge_offset = totedge + (totvert * (step_tot - (close ? 0 : 1)));
const int *src_material_index = BKE_mesh_material_indices(mesh);
int *dst_material_index = BKE_mesh_material_indices_for_write(result);
for (i = 0; i < totedge; i++, med_new_firstloop++) {
const uint step_last = step_tot - (close ? 1 : 2);
const uint mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX;
@ -959,14 +962,14 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
};
const bool has_mloop_orig = mloop_index_orig[0] != UINT_MAX;
short mat_nr;
int mat_nr;
/* for each edge, make a cylinder of quads */
i1 = med_new_firstloop->v1;
i2 = med_new_firstloop->v2;
if (has_mpoly_orig) {
mat_nr = mpoly_orig[mpoly_index_orig].mat_nr;
mat_nr = src_material_index == NULL ? 0 : src_material_index[mpoly_index_orig];
}
else {
mat_nr = 0;
@ -992,8 +995,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
else {
origindex[mpoly_index] = ORIGINDEX_NONE;
dst_material_index[mpoly_index] = mat_nr;
mp_new->flag = mpoly_flag;
mp_new->mat_nr = mat_nr;
}
mp_new->loopstart = mpoly_index * 4;
mp_new->totloop = 4;

View File

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

View File

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

View File

@ -23,19 +23,30 @@ static void node_declare(NodeDeclarationBuilder &b)
static void select_mesh_by_material(const Mesh &mesh,
const Material *material,
const IndexMask mask,
const MutableSpan<bool> r_selection)
MutableSpan<bool> r_selection)
{
BLI_assert(mesh.totpoly >= r_selection.size());
Vector<int> material_indices;
Vector<int> slots;
for (const int i : IndexRange(mesh.totcol)) {
if (mesh.mat[i] == material) {
material_indices.append(i);
slots.append(i);
}
}
const AttributeAccessor attributes = bke::mesh_attributes(mesh);
const VArray<int> material_indices = attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
if (material != nullptr && material_indices.is_single() &&
material_indices.get_internal_single() == 0) {
r_selection.fill_indices(mask, false);
return;
}
const VArraySpan<int> material_indices_span(material_indices);
threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
const int face_index = mask[i];
r_selection[i] = material_indices.contains(mesh.mpoly[face_index].mat_nr);
r_selection[i] = slots.contains(material_indices_span[face_index]);
}
});
}

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

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

View File

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