diff options
author | Hans Goudey <h.goudey@me.com> | 2022-08-31 17:09:01 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-08-31 17:09:01 +0300 |
commit | f1c0249f34c4171ec311b5b9882e36fed5889259 (patch) | |
tree | 7dd630c9301b8dd468c8279e8c446c62824fb6d6 /source/blender/io/wavefront_obj | |
parent | 3e73afb5360592fe2bf43419e216035ea3c281f9 (diff) |
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
Diffstat (limited to 'source/blender/io/wavefront_obj')
4 files changed, 30 insertions, 24 deletions
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc index 9bcc061caf7..902f801ee5b 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc @@ -374,10 +374,14 @@ void OBJWriter::write_poly_elements(FormatHandler &fh, } } + const bke::AttributeAccessor attributes = bke::mesh_attributes(*obj_mesh_data.get_mesh()); + const VArray<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + /* Write material name and material group if different from previous. */ if (export_params_.export_materials && obj_mesh_data.tot_materials() > 0) { - const int16_t prev_mat = idx == 0 ? NEGATIVE_INIT : obj_mesh_data.ith_poly_matnr(prev_i); - const int16_t mat = obj_mesh_data.ith_poly_matnr(i); + const int16_t prev_mat = idx == 0 ? NEGATIVE_INIT : std::max(0, material_indices[prev_i]); + const int16_t mat = std::max(0, material_indices[i]); if (mat != prev_mat) { if (mat == NOT_FOUND) { buf.write_obj_usemtl(MATERIAL_GROUP_DISABLED); diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc index 815163ad19e..a888c6d11a2 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -6,6 +6,7 @@ /* Silence warnings from copying deprecated fields. Needed for an Object copy constructor use. */ #define DNA_DEPRECATED_ALLOW +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_lib_id.h" @@ -199,16 +200,23 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags) void OBJMesh::calc_poly_order() { - const int tot_polys = tot_polygons(); - poly_order_.resize(tot_polys); - for (int i = 0; i < tot_polys; ++i) { + const bke::AttributeAccessor attributes = bke::mesh_attributes(*export_mesh_eval_); + const VArray<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + if (material_indices.is_single() && material_indices.get_internal_single() == 0) { + return; + } + const VArraySpan<int> material_indices_span(material_indices); + + poly_order_.resize(material_indices_span.size()); + for (const int i : material_indices_span.index_range()) { poly_order_[i] = i; } - const MPoly *mpolys = export_mesh_eval_->mpoly; + /* Sort polygons by their material index. */ blender::parallel_sort(poly_order_.begin(), poly_order_.end(), [&](int a, int b) { - int mat_a = mpolys[a].mat_nr; - int mat_b = mpolys[b].mat_nr; + int mat_a = material_indices_span[a]; + int mat_b = material_indices_span[b]; if (mat_a != mat_b) { return mat_a < mat_b; } @@ -234,13 +242,6 @@ bool OBJMesh::is_ith_poly_smooth(const int poly_index) const return export_mesh_eval_->mpoly[poly_index].flag & ME_SMOOTH; } -int16_t OBJMesh::ith_poly_matnr(const int poly_index) const -{ - BLI_assert(poly_index < export_mesh_eval_->totpoly); - const int16_t r_mat_nr = export_mesh_eval_->mpoly[poly_index].mat_nr; - return r_mat_nr >= 0 ? r_mat_nr : NOT_FOUND; -} - const char *OBJMesh::get_object_name() const { return export_object_eval_.id.name + 2; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh index ee2e6227700..db29f5651ed 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh @@ -130,11 +130,6 @@ class OBJMesh : NonCopyable { * Return mat_nr-th material of the object. The given index should be zero-based. */ const Material *get_object_material(int16_t mat_nr) const; - /** - * Returns a zero-based index of a polygon's material indexing into - * the Object's material slots. - */ - int16_t ith_poly_matnr(int poly_index) const; void ensure_mesh_normals() const; void ensure_mesh_edges() const; diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc index 2a0676b72ff..7f7fda8d8f1 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc @@ -8,7 +8,7 @@ #include "DNA_mesh_types.h" #include "DNA_scene_types.h" -#include "BKE_attribute.h" +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_material.h" @@ -184,6 +184,10 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, nullptr, total_verts)); } + bke::SpanAttributeWriter<int> material_indices = + bke::mesh_attributes_for_write(*mesh).lookup_or_add_for_write_only_span<int>( + "material_index", ATTR_DOMAIN_FACE); + const int64_t tot_face_elems{mesh->totpoly}; int tot_loop_idx = 0; @@ -201,11 +205,11 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) if (curr_face.shaded_smooth) { mpoly.flag |= ME_SMOOTH; } - mpoly.mat_nr = curr_face.material_index; + material_indices.span[poly_idx] = curr_face.material_index; /* Importing obj files without any materials would result in negative indices, which is not * supported. */ - if (mpoly.mat_nr < 0) { - mpoly.mat_nr = 0; + if (material_indices.span[poly_idx] < 0) { + material_indices.span[poly_idx] = 0; } for (int idx = 0; idx < curr_face.corner_count_; ++idx) { @@ -223,6 +227,8 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) dw->weight = 1.0f; } } + + material_indices.finish(); } void MeshFromGeometry::create_vertex_groups(Object *obj) |