[Bf-blender-cvs] [1b4f35f6a58] master: obj: vertex colors support in importer and exporter

Aras Pranckevicius noreply at git.blender.org
Tue Jun 14 09:19:09 CEST 2022


Commit: 1b4f35f6a5889d8d2e65c6231e84f8b1744c4f96
Author: Aras Pranckevicius
Date:   Tue Jun 14 10:19:02 2022 +0300
Branches: master
https://developer.blender.org/rB1b4f35f6a5889d8d2e65c6231e84f8b1744c4f96

obj: vertex colors support in importer and exporter

Adds support for vertex colors to OBJ I/O.

Importer:

- Supports both "xyzrgb" and "MRGB" vertex color formats.
- Whenever vertex color is present in the file for a model, it is
  imported and a Color attribute is created (per-vertex, full float
  color data type). Color coming from the file is assumed to be sRGB,
  and is converted to linear upon import.

Exporter:

- Option to export the vertex colors. Defaults to "off", since not
  all 3rd party software supports vertex colors.
- When the option is "on", if a mesh has a color attribute layer,
  the active one is exported in "xyzrgb" form. If the mesh has
  per-face-corner colors, they are averaged on the vertices.
  Colors are converted from linear to sRGB upon export.

Reviewed By: Howard Trickey
Differential Revision: https://developer.blender.org/D15159

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

M	source/blender/editors/io/io_obj.c
M	source/blender/io/wavefront_obj/IO_wavefront_obj.h
M	source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
M	source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
M	source/blender/io/wavefront_obj/exporter/obj_export_io.hh
M	source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
M	source/blender/io/wavefront_obj/exporter/obj_exporter.cc
M	source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
M	source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
M	source/blender/io/wavefront_obj/importer/obj_import_mesh.hh
M	source/blender/io/wavefront_obj/importer/obj_import_objects.hh
M	source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
M	source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
M	source/blender/io/wavefront_obj/tests/obj_importer_tests.cc

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

diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index a8eed136df3..4819ae09785 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -100,6 +100,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
   export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects");
   export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv");
   export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals");
+  export_params.export_colors = RNA_boolean_get(op->ptr, "export_colors");
   export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials");
   export_params.path_mode = RNA_enum_get(op->ptr, "path_mode");
   export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
@@ -160,6 +161,7 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
   sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export"));
   uiItemR(sub, imfptr, "export_uv", 0, IFACE_("UV Coordinates"), ICON_NONE);
   uiItemR(sub, imfptr, "export_normals", 0, IFACE_("Normals"), ICON_NONE);
+  uiItemR(sub, imfptr, "export_colors", 0, IFACE_("Colors"), ICON_NONE);
   uiItemR(sub, imfptr, "export_materials", 0, IFACE_("Materials"), ICON_NONE);
   uiItemR(sub, imfptr, "export_triangulated_mesh", 0, IFACE_("Triangulated Mesh"), ICON_NONE);
   uiItemR(sub, imfptr, "export_curves_as_nurbs", 0, IFACE_("Curves as NURBS"), ICON_NONE);
@@ -315,6 +317,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
                   "Export Normals",
                   "Export per-face normals if the face is flat-shaded, per-face-per-loop "
                   "normals if smooth-shaded");
+  RNA_def_boolean(ot->srna, "export_colors", false, "Export Colors", "Export per-vertex colors");
   RNA_def_boolean(ot->srna,
                   "export_materials",
                   true,
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
index 0a78cdc714d..a719dff2126 100644
--- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -45,6 +45,7 @@ struct OBJExportParams {
   eEvaluationMode export_eval_mode;
   bool export_uv;
   bool export_normals;
+  bool export_colors;
   bool export_materials;
   bool export_triangulated_mesh;
   bool export_curves_as_nurbs;
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 11d1bafdafe..cb95c561547 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
@@ -8,7 +8,9 @@
 #include <cstdio>
 
 #include "BKE_blender_version.h"
+#include "BKE_geometry_set.hh"
 
+#include "BLI_color.hh"
 #include "BLI_enumerable_thread_specific.hh"
 #include "BLI_path_util.h"
 #include "BLI_task.hh"
@@ -241,13 +243,38 @@ void obj_parallel_chunked_output(FormatHandler<eFileType::OBJ> &fh,
 }
 
 void OBJWriter::write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
-                                    const OBJMesh &obj_mesh_data) const
+                                    const OBJMesh &obj_mesh_data,
+                                    bool write_colors) const
 {
   const int tot_count = obj_mesh_data.tot_vertices();
-  obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
-    float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
-    buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
-  });
+
+  Mesh *mesh = obj_mesh_data.get_mesh();
+  CustomDataLayer *colors_layer = nullptr;
+  if (write_colors) {
+    colors_layer = BKE_id_attributes_active_color_get(&mesh->id);
+  }
+  if (write_colors && (colors_layer != nullptr)) {
+    MeshComponent component;
+    component.replace(mesh, GeometryOwnershipType::ReadOnly);
+    VArray<ColorGeometry4f> attribute = component.attribute_get_for_read<ColorGeometry4f>(
+        colors_layer->name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f});
+
+    BLI_assert(tot_count == attribute.size());
+    obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
+      float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+      ColorGeometry4f linear = attribute.get(i);
+      float srgb[3];
+      linearrgb_to_srgb_v3_v3(srgb, linear);
+      buf.write<eOBJSyntaxElement::vertex_coords_color>(
+          vertex[0], vertex[1], vertex[2], srgb[0], srgb[1], srgb[2]);
+    });
+  }
+  else {
+    obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
+      float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+      buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
+    });
+  }
 }
 
 void OBJWriter::write_uv_coords(FormatHandler<eFileType::OBJ> &fh, OBJMesh &r_obj_mesh_data) const
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
index 77da7b44276..97c23484426 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
@@ -72,9 +72,11 @@ class OBJWriter : NonMovable, NonCopyable {
    */
   void write_mtllib_name(const StringRefNull mtl_filepath) const;
   /**
-   * Write vertex coordinates for all vertices as "v x y z".
+   * Write vertex coordinates for all vertices as "v x y z" or "v x y z r g b".
    */
-  void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const;
+  void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
+                           const OBJMesh &obj_mesh_data,
+                           bool write_colors) const;
   /**
    * Write UV vertex coordinates for all vertices as `vt u v`.
    * \note UV indices are stored here, but written with polygons later.
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
index f0263989bfc..157d7760307 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
@@ -30,6 +30,7 @@ enum class eFileType {
 
 enum class eOBJSyntaxElement {
   vertex_coords,
+  vertex_coords_color,
   uv_vertex_coords,
   normal,
   poly_element_begin,
@@ -130,6 +131,9 @@ constexpr FormattingSyntax syntax_elem_to_formatting(const eOBJSyntaxElement key
     case eOBJSyntaxElement::vertex_coords: {
       return {"v {:.6f} {:.6f} {:.6f}\n", 3, is_type_float<T...>};
     }
+    case eOBJSyntaxElement::vertex_coords_color: {
+      return {"v {:.6f} {:.6f} {:.6f} {:.6f} {:.6f} {:.6f}\n", 6, is_type_float<T...>};
+    }
     case eOBJSyntaxElement::uv_vertex_coords: {
       return {"vt {:.6f} {:.6f}\n", 2, is_type_float<T...>};
     }
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 91213ec8152..ee2e6227700 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
@@ -241,6 +241,11 @@ class OBJMesh : NonCopyable {
     return i < 0 || i >= poly_order_.size() ? i : poly_order_[i];
   }
 
+  Mesh *get_mesh() const
+  {
+    return export_mesh_eval_;
+  }
+
  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 b6e636b389d..b0938084efb 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
@@ -195,7 +195,7 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me
       auto &fh = buffers[i];
 
       obj_writer.write_object_name(fh, obj);
-      obj_writer.write_vertex_coords(fh, obj);
+      obj_writer.write_vertex_coords(fh, obj, export_params.export_colors);
 
       if (obj.tot_polygons() > 0) {
         if (export_params.export_smooth_groups) {
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
index a627e7261e3..4a27d734819 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
@@ -5,12 +5,15 @@
  */
 
 #include "BLI_map.hh"
+#include "BLI_math_color.h"
 #include "BLI_string_ref.hh"
 #include "BLI_vector.hh"
 
 #include "obj_import_file_reader.hh"
 #include "obj_import_string_utils.hh"
 
+#include <charconv>
+
 namespace blender::io::obj {
 
 using std::string;
@@ -34,6 +37,7 @@ static Geometry *create_geometry(Geometry *const prev_geometry,
     g->geom_type_ = new_type;
     g->geometry_name_ = name.is_empty() ? "New object" : name;
     g->vertex_start_ = global_vertices.vertices.size();
+    g->vertex_color_start_ = global_vertices.vertex_colors.size();
     r_offset.set_index_offset(g->vertex_start_);
     return g;
   };
@@ -71,9 +75,51 @@ static void geom_add_vertex(Geometry *geom,
                             GlobalVertices &r_global_vertices)
 {
   float3 vert;
-  parse_floats(p, end, 0.0f, vert, 3);
+  p = parse_floats(p, end, 0.0f, vert, 3);
   r_global_vertices.vertices.append(vert);
   geom->vertex_count_++;
+  /* OBJ extension: "xyzrgb" vertex colors, when the vertex position
+   * is followed by 3 more RGB color components. See
+   * http://paulbourke.net/dataformats/obj/colour.html */
+  if (p < end) {
+    float3 srgb;
+    p = parse_floats(p, end, -1.0f, srgb, 3);
+    if (srgb.x >= 0 && srgb.y >= 0 && srgb.z >= 0) {
+      float3 linear;
+      srgb_to_linearrgb_v3_v3(linear, srgb);
+      r_global_vertices.vertex_colors.append(linear);
+      geom->vertex_color_count_++;
+    }
+  }
+}
+
+static void geom_add_mrgb_colors(Geometry *geom,
+                                 co

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list