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. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs