Commit: a99a62231e040a15c93add9ffa582ec9e1d9c4f1 Author: Aras Pranckevicius Date: Tue Sep 13 13:28:57 2022 +0300 Branches: master https://developer.blender.org/rBa99a62231e040a15c93add9ffa582ec9e1d9c4f1
obj: implement support for PBR .mtl extensions Implement import & export support for "PBR extensions" in .mtl files (T101029, also fixes T86736). Newly supported parameters: - Roughness (Pr, map_Pr) - Metallic (Pm, map_Pm) - Sheen (Ps, map_Ps) - Clearcoat thickness (Pc) and roughness (Pcr) - Anisotropy (aniso) and rotation (anisor) - Transmittance (Tf / Kt) Exporter has an option to enable these additional PBR parameters export; defaults to off since not all software understands that. Exporter UI tweaked and all material-related options were put into their own separate box. Added/extended test files in Subversion repository for test coverage. =================================================================== 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_mtl.cc M source/blender/io/wavefront_obj/exporter/obj_export_mtl.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_mtl.cc 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_mtl_parser_tests.cc =================================================================== diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c index 619d8a34132..cb8eafeb52d 100644 --- a/source/blender/editors/io/io_obj.c +++ b/source/blender/editors/io/io_obj.c @@ -93,6 +93,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op) export_params.path_mode = RNA_enum_get(op->ptr, "path_mode"); export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh"); export_params.export_curves_as_nurbs = RNA_boolean_get(op->ptr, "export_curves_as_nurbs"); + export_params.export_pbr_extensions = RNA_boolean_get(op->ptr, "export_pbr_extensions"); export_params.export_object_groups = RNA_boolean_get(op->ptr, "export_object_groups"); export_params.export_material_groups = RNA_boolean_get(op->ptr, "export_material_groups"); @@ -118,7 +119,6 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr) /* Object Transform options. */ box = uiLayoutBox(layout); - uiItemL(box, IFACE_("Object Properties"), ICON_OBJECT_DATA); col = uiLayoutColumn(box, false); sub = uiLayoutColumnWithHeading(col, false, IFACE_("Limit to")); uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE); @@ -134,27 +134,31 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr) sub = uiLayoutColumnWithHeading(col, false, IFACE_("Objects")); uiItemR(sub, imfptr, "apply_modifiers", 0, IFACE_("Apply Modifiers"), ICON_NONE); uiItemR(sub, imfptr, "export_eval_mode", 0, IFACE_("Properties"), ICON_NONE); - sub = uiLayoutColumn(sub, false); - uiLayoutSetEnabled(sub, export_materials); - uiItemR(sub, imfptr, "path_mode", 0, IFACE_("Path Mode"), ICON_NONE); - /* Options for what to write. */ + /* Geometry options. */ box = uiLayoutBox(layout); - uiItemL(box, IFACE_("Geometry"), ICON_EXPORT); col = uiLayoutColumn(box, false); - sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export")); + sub = uiLayoutColumnWithHeading(col, false, IFACE_("Geometry")); 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); + /* Material options. */ + box = uiLayoutBox(layout); + col = uiLayoutColumn(box, false); + sub = uiLayoutColumnWithHeading(col, false, IFACE_("Materials")); + uiItemR(sub, imfptr, "export_materials", 0, IFACE_("Export"), ICON_NONE); + sub = uiLayoutColumn(sub, false); + uiLayoutSetEnabled(sub, export_materials); + uiItemR(sub, imfptr, "export_pbr_extensions", 0, IFACE_("PBR Extensions"), ICON_NONE); + uiItemR(sub, imfptr, "path_mode", 0, IFACE_("Path Mode"), ICON_NONE); + /* Grouping options. */ box = uiLayoutBox(layout); - uiItemL(box, IFACE_("Grouping"), ICON_GROUP); col = uiLayoutColumn(box, false); - sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export")); + sub = uiLayoutColumnWithHeading(col, false, IFACE_("Grouping")); uiItemR(sub, imfptr, "export_object_groups", 0, IFACE_("Object Groups"), ICON_NONE); uiItemR(sub, imfptr, "export_material_groups", 0, IFACE_("Material Groups"), ICON_NONE); uiItemR(sub, imfptr, "export_vertex_groups", 0, IFACE_("Vertex Groups"), ICON_NONE); @@ -165,14 +169,13 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr) /* Animation options. */ box = uiLayoutBox(layout); - uiItemL(box, IFACE_("Animation"), ICON_ANIM); col = uiLayoutColumn(box, false); - sub = uiLayoutColumn(col, false); - uiItemR(sub, imfptr, "export_animation", 0, NULL, ICON_NONE); + sub = uiLayoutColumnWithHeading(col, false, IFACE_("Animation")); + uiItemR(sub, imfptr, "export_animation", 0, IFACE_("Export"), ICON_NONE); sub = uiLayoutColumn(sub, true); + uiLayoutSetEnabled(sub, export_animation); uiItemR(sub, imfptr, "start_frame", 0, IFACE_("Frame Start"), ICON_NONE); uiItemR(sub, imfptr, "end_frame", 0, IFACE_("End"), ICON_NONE); - uiLayoutSetEnabled(sub, export_animation); } static void wm_obj_export_draw(bContext *UNUSED(C), wmOperator *op) @@ -336,6 +339,12 @@ void WM_OT_obj_export(struct wmOperatorType *ot) "Export Materials", "Export MTL library. There must be a Principled-BSDF node for image textures to " "be exported to the MTL file"); + RNA_def_boolean(ot->srna, + "export_pbr_extensions", + false, + "Export Materials with PBR Extensions", + "Export MTL library using PBR extensions (roughness, metallic, sheen, " + "clearcoat, anisotropy, transmission)"); RNA_def_enum(ot->srna, "path_mode", io_obj_path_mode, diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h index 544630c9cc0..0a92bbca477 100644 --- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h +++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h @@ -48,18 +48,15 @@ struct OBJExportParams { bool export_triangulated_mesh; bool export_curves_as_nurbs; ePathReferenceMode path_mode; + bool export_pbr_extensions; /* Grouping options. */ bool export_object_groups; bool export_material_groups; bool export_vertex_groups; - /** - * Calculate smooth groups from sharp edges. - */ + /* Calculate smooth groups from sharp edges. */ bool export_smooth_groups; - /** - * Create bitflags instead of the default "0"/"1" group IDs. - */ + /* Create bitflags instead of the default "0"/"1" group IDs. */ bool smooth_groups_bitflags; }; 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 27526734624..f2547e6fc14 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 @@ -493,11 +493,14 @@ void OBJWriter::write_nurbs_curve(FormatHandler &fh, const OBJCurve &obj_nurbs_d static const char *tex_map_type_to_string[] = { "map_Kd", + "map_Pm", "map_Ks", "map_Ns", - "map_d", + "map_Pr", + "map_Ps", "map_refl", "map_Ke", + "map_d", "map_Bump", }; BLI_STATIC_ASSERT(ARRAY_SIZE(tex_map_type_to_string) == (int)MTLTexMapType::Count, @@ -553,16 +556,20 @@ StringRefNull MTLWriter::mtl_file_path() const return mtl_filepath_; } -void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl) +void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl, bool write_pbr) { /* For various material properties, we only capture information * coming from the texture, or the default value of the socket. * When the texture is present, do not emit the default value. */ - if (!mtl.tex_map_of_type(MTLTexMapType::SpecularExponent).is_valid()) { - fmt_handler_.write_mtl_float("Ns", mtl.spec_exponent); + + /* Do not write Ns & Ka when writing in PBR mode. */ + if (!write_pbr) { + if (!mtl.tex_map_of_type(MTLTexMapType::SpecularExponent).is_valid()) { + fmt_handler_.write_mtl_float("Ns", mtl.spec_exponent); + } + fmt_handler_.write_mtl_float3( + "Ka", mtl.ambient_color.x, mtl.ambient_color.y, mtl.ambient_color.z); } - fmt_handler_.write_mtl_float3( - "Ka", mtl.ambient_color.x, mtl.ambient_color.y, mtl.ambient_color.z); if (!mtl.tex_map_of_type(MTLTexMapType::Color).is_valid()) { fmt_handler_.write_mtl_float3("Kd", mtl.color.x, mtl.color.y, mtl.color.z); } @@ -578,6 +585,35 @@ void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl) fmt_handler_.write_mtl_float("d", mtl.alpha); } fmt_handler_.write_mtl_illum(mtl.illum_mode); + + if (write_pbr) { + if (!mtl.tex_map_of_type(MTLTexMapType::Roughness).is_valid() && mtl.roughness >= 0.0f) { + fmt_handler_.write_mtl_float("Pr", mtl.roughness); + } + if (!mtl.tex_map_of_type(MTLTexMapType::Metallic).is_valid() && mtl.metallic >= 0.0f) { + fmt_handler_.write_mtl_float("Pm", mtl.metallic); + } + if (!mtl.tex_map_of_type(MTLTexMapType::Sheen).is_valid() && mtl.sheen >= 0.0f) { + fmt_handler_.write_mtl_float("Ps", mtl.sheen); + } + if (mtl.cc_thickness >= 0.0f) { + fmt_handler_.write_mtl_float("Pc", mtl.cc_thickness); + } + if (mtl.cc_roughness >= 0.0f) { + fmt_handler_.write_mtl_float("Pcr", mtl.cc_roughness); + } + if (mtl.aniso >= 0.0f) { + fmt_handler_.write_mtl_float("aniso", mtl.aniso); + } + if (mtl.aniso_rot >= 0.0f) { + fmt_handler_.write_mtl_float("anisor", mtl.aniso_rot); + } + if (mtl.transmit_color.x > 0.0f || mtl.transmit_color.y > 0.0f || + mtl.transmit_color.z > 0.0f) { + fmt_handler_.write_mtl_float3( + "Tf", mtl.transmit_color.x, mtl.transmit_color.y, mtl.transmit_color.z); + } + } } void MTLWriter::write_texture_map(const MTLMaterial &mtl_material, @@ -608,9 +644,21 @@ void MTLWriter::write_texture_map(const MTLMaterial &mtl_material, fmt_handler_.write_mtl_map(tex_map_type_to_string[(int)texture_key], options, path); } +static bool is_pbr_map(MTLTexMapType type) +{ + return type == MTLTexMapType::Metallic || type == MTLTexMapType::Roughness || + type == MTLTexMapType::Sheen; +} + +static bool is_non_pbr_map(MTLTexMapType type) +{ + return type == MTLTexMapType::SpecularExponent || type == MTLTexMapType::Reflection; +} + void MTLWriter::write_materials(const char *blen_filepath, ePathReferenceMode path_mode, - const char *dest_dir) + const char *dest_dir, + bool write_pbr) { if (mtlmaterials_.size() == 0) { return; @@ -628,12 +676,18 @@ void MTLWriter::write_materials(const char *blen_filepath, for (const MTLMaterial &mtlmat : mtlmate @@ 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