[Bf-blender-cvs] [b444ed2b383] blender-v3.1-release: Fix T96511: New OBJ exporter no longer groups faces by material

Aras Pranckevicius noreply at git.blender.org
Wed Mar 23 12:23:11 CET 2022


Commit: b444ed2b3835f46b63c0d398ac499debbec291a2
Author: Aras Pranckevicius
Date:   Mon Mar 21 20:15:36 2022 +0200
Branches: blender-v3.1-release
https://developer.blender.org/rBb444ed2b3835f46b63c0d398ac499debbec291a2

Fix T96511: New OBJ exporter no longer groups faces by material

Old python exporter in 3.0 and earlier ordered faces by material,
but the new C++ exporter in 3.1+ did not, and was just writing them
in whatever is the order of the mesh data structure.

This mostly does not cause problems, except in some apps e.g.
Procreate -- for large enough meshes, this lack of
"order by material" (which ends up having more usemtl lines)
ends up creating more mesh subsets than necessary inside Procreate.

The change is not computationally heavy, e.g. exporting 6-level
subdivided Monkey mesh goes 1085ms -> 1105ms on my machine.

Reviewed By: @howardt
Differential Revision: https://developer.blender.org/D14368
Cherry-picked from: eb1755be355a + fab14f78542c + 8c072cdc935c

===================================================================

M	source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
M	source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
M	source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
M	source/blender/io/wavefront_obj/exporter/obj_exporter.cc

===================================================================

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 302b20783c2..24a1b61d104 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
@@ -325,7 +325,12 @@ void OBJWriter::write_poly_elements(const OBJMesh &obj_mesh_data,
       obj_mesh_data.tot_uv_vertices());
 
   const int tot_polygons = obj_mesh_data.tot_polygons();
-  for (int i = 0; i < tot_polygons; i++) {
+  for (int idx = 0; idx < tot_polygons; idx++) {
+    /* Polygon order for writing into the file is not necessarily the same
+     * as order in the mesh; it will be sorted by material indices. Remap current
+     * index here according to the order. */
+    int i = obj_mesh_data.remap_poly_index(idx);
+
     Vector<int> poly_vertex_indices = obj_mesh_data.calc_poly_vertex_indices(i);
     Span<int> poly_uv_indices = obj_mesh_data.calc_poly_uv_indices(i);
     Vector<int> poly_normal_indices = obj_mesh_data.calc_poly_normal_indices(i);
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 fd831aa5674..93aba14aa0b 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
@@ -195,6 +195,25 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags)
                                                    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) {
+    poly_order_[i] = i;
+  }
+  const MPoly *mpolys = export_mesh_eval_->mpoly;
+  /* Sort polygons by their material index. */
+  std::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;
+    if (mat_a != mat_b) {
+      return mat_a < mat_b;
+    }
+    return a < b;
+  });
+}
+
 const Material *OBJMesh::get_object_material(const int16_t mat_nr) const
 {
   /**
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 3ec670d2203..4ab7567aa0f 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
@@ -101,6 +101,10 @@ class OBJMesh : NonCopyable {
    * Polygon aligned array of their smooth groups.
    */
   int *poly_smooth_groups_ = nullptr;
+  /**
+   * Order in which the polygons should be written into the file (sorted by material index).
+   */
+  Vector<int> poly_order_;
 
  public:
   /**
@@ -212,6 +216,22 @@ class OBJMesh : NonCopyable {
    */
   std::optional<std::array<int, 2>> calc_loose_edge_vert_indices(int edge_index) const;
 
+  /**
+   * Calculate the order in which the polygons should be written into the file (sorted by material
+   * index).
+   */
+  void calc_poly_order();
+
+  /**
+   * Remap polygon index according to polygon writing order.
+   * When materials are not being written, the polygon order array
+   * might be empty, in which case remap is a no-op.
+   */
+  int remap_poly_index(int i) const
+  {
+    return i < 0 || i >= poly_order_.size() ? i : poly_order_[i];
+  }
+
  private:
   /**
    * Free the mesh if _the exporter_ created it.
diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
index 0c753ccdcac..330002df0a7 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
@@ -171,6 +171,9 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me
       if (export_params.export_smooth_groups) {
         obj_mesh->calc_smooth_groups(export_params.smooth_groups_bitflags);
       }
+      if (export_params.export_materials) {
+        obj_mesh->calc_poly_order();
+      }
       if (export_params.export_normals) {
         obj_writer.write_poly_normals(*obj_mesh);
       }



More information about the Bf-blender-cvs mailing list