Commit: e6a9b223844346a34ce195652449fec3229a2ec1 Author: Ankit Meel Date: Mon Apr 4 13:36:10 2022 +0300 Branches: master https://developer.blender.org/rBe6a9b223844346a34ce195652449fec3229a2ec1
OBJ: New C++ based wavefront OBJ importer This takes state of soc-2020-io-performance branch as it was at e9bbfd0c8c7 (2021 Oct 31), merges latest master (2022 Apr 4), adds a bunch of tests, and fixes a bunch of stuff found by said tests. The fixes are detailed in the differential. Timings on my machine (Windows, VS2022 release build, AMD Ryzen 5950X 32 threads): - Rungholt minecraft level (269MB file, 1 mesh): 54.2s -> 14.2s (memory usage: 7.0GB -> 1.9GB). - Blender 3.0 splash scene: "I waited for 90 minutes and gave up" -> 109s. Now, this time is not great, but at least 20% of the time is spent assigning unique names for the imported objects (the scene has 24 thousand objects). This is not specific to obj importer, but rather a general issue across blender overall. Test suite file updates done in Subversion tests repository. Reviewed By: @howardt, @sybren Differential Revision: https://developer.blender.org/D13958 =================================================================== M release/scripts/startup/bl_ui/space_topbar.py M source/blender/editors/io/io_obj.c M source/blender/editors/io/io_obj.h M source/blender/editors/io/io_ops.c M source/blender/io/wavefront_obj/CMakeLists.txt M source/blender/io/wavefront_obj/IO_wavefront_obj.cc M source/blender/io/wavefront_obj/IO_wavefront_obj.h A source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc A source/blender/io/wavefront_obj/importer/importer_mesh_utils.hh A source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc A source/blender/io/wavefront_obj/importer/obj_import_file_reader.hh A source/blender/io/wavefront_obj/importer/obj_import_mesh.cc A source/blender/io/wavefront_obj/importer/obj_import_mesh.hh A source/blender/io/wavefront_obj/importer/obj_import_mtl.cc A source/blender/io/wavefront_obj/importer/obj_import_mtl.hh A source/blender/io/wavefront_obj/importer/obj_import_nurbs.cc A source/blender/io/wavefront_obj/importer/obj_import_nurbs.hh A source/blender/io/wavefront_obj/importer/obj_import_objects.hh A source/blender/io/wavefront_obj/importer/obj_importer.cc A source/blender/io/wavefront_obj/importer/obj_importer.hh A source/blender/io/wavefront_obj/importer/parser_string_utils.cc A source/blender/io/wavefront_obj/importer/parser_string_utils.hh A source/blender/io/wavefront_obj/tests/obj_importer_tests.cc =================================================================== diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py index 0a428b4ea3f..55dcb4a20eb 100644 --- a/release/scripts/startup/bl_ui/space_topbar.py +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -456,6 +456,7 @@ class TOPBAR_MT_file_import(Menu): "wm.usd_import", text="Universal Scene Description (.usd, .usdc, .usda)") self.layout.operator("wm.gpencil_import_svg", text="SVG as Grease Pencil") + self.layout.operator("wm.obj_import", text="Wavefront (.obj) (experimental)") class TOPBAR_MT_file_export(Menu): diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c index df15191916a..97f1e08fdff 100644 --- a/source/blender/editors/io/io_obj.c +++ b/source/blender/editors/io/io_obj.c @@ -359,3 +359,87 @@ void WM_OT_obj_export(struct wmOperatorType *ot) RNA_def_boolean( ot->srna, "smooth_group_bitflags", false, "Generate Bitflags for Smooth Groups", ""); } + +static int wm_obj_import_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + WM_event_add_fileselect(C, op); + return OPERATOR_RUNNING_MODAL; +} + +static int wm_obj_import_exec(bContext *C, wmOperator *op) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + + struct OBJImportParams import_params; + RNA_string_get(op->ptr, "filepath", import_params.filepath); + import_params.clamp_size = RNA_float_get(op->ptr, "clamp_size"); + import_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis"); + import_params.up_axis = RNA_enum_get(op->ptr, "up_axis"); + + OBJ_import(C, &import_params); + + return OPERATOR_FINISHED; +} + +static void ui_obj_import_settings(uiLayout *layout, PointerRNA *imfptr) +{ + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + uiLayout *box = uiLayoutBox(layout); + + uiItemL(box, IFACE_("Transform"), ICON_OBJECT_DATA); + uiLayout *col = uiLayoutColumn(box, false); + uiLayout *sub = uiLayoutColumn(col, false); + uiItemR(sub, imfptr, "clamp_size", 0, NULL, ICON_NONE); + sub = uiLayoutColumn(col, false); + uiItemR(sub, imfptr, "forward_axis", 0, IFACE_("Axis Forward"), ICON_NONE); + uiItemR(sub, imfptr, "up_axis", 0, IFACE_("Up"), ICON_NONE); +} + +static void wm_obj_import_draw(bContext *C, wmOperator *op) +{ + PointerRNA ptr; + wmWindowManager *wm = CTX_wm_manager(C); + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + ui_obj_import_settings(op->layout, &ptr); +} + +void WM_OT_obj_import(struct wmOperatorType *ot) +{ + ot->name = "Import Wavefront OBJ"; + ot->description = "Load a Wavefront OBJ scene"; + ot->idname = "WM_OT_obj_import"; + + ot->invoke = wm_obj_import_invoke; + ot->exec = wm_obj_import_exec; + ot->poll = WM_operator_winactive; + ot->ui = wm_obj_import_draw; + + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO, + FILE_BLENDER, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS, + FILE_DEFAULTDISPLAY, + FILE_SORT_ALPHA); + RNA_def_float( + ot->srna, + "clamp_size", + 0.0f, + 0.0f, + 1000.0f, + "Clamp Bounding Box", + "Resize the objects to keep bounding box under this value. Value 0 diables clamping", + 0.0f, + 1000.0f); + RNA_def_enum(ot->srna, + "forward_axis", + io_obj_transform_axis_forward, + OBJ_AXIS_NEGATIVE_Z_FORWARD, + "Forward Axis", + ""); + RNA_def_enum(ot->srna, "up_axis", io_obj_transform_axis_up, OBJ_AXIS_Y_UP, "Up Axis", ""); +} diff --git a/source/blender/editors/io/io_obj.h b/source/blender/editors/io/io_obj.h index cb9cdc8e74d..30857b33f21 100644 --- a/source/blender/editors/io/io_obj.h +++ b/source/blender/editors/io/io_obj.h @@ -9,3 +9,4 @@ struct wmOperatorType; void WM_OT_obj_export(struct wmOperatorType *ot); +void WM_OT_obj_import(struct wmOperatorType *ot); diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c index ccd19608ddd..094f89d1540 100644 --- a/source/blender/editors/io/io_ops.c +++ b/source/blender/editors/io/io_ops.c @@ -59,4 +59,5 @@ void ED_operatortypes_io(void) WM_operatortype_append(CACHEFILE_OT_layer_move); WM_operatortype_append(WM_OT_obj_export); + WM_operatortype_append(WM_OT_obj_import); } diff --git a/source/blender/io/wavefront_obj/CMakeLists.txt b/source/blender/io/wavefront_obj/CMakeLists.txt index cc375577b52..9cdd96ee7be 100644 --- a/source/blender/io/wavefront_obj/CMakeLists.txt +++ b/source/blender/io/wavefront_obj/CMakeLists.txt @@ -3,6 +3,7 @@ set(INC . ./exporter + ./importer ../../blenkernel ../../blenlib ../../bmesh @@ -28,6 +29,13 @@ set(SRC exporter/obj_export_mtl.cc exporter/obj_export_nurbs.cc exporter/obj_exporter.cc + importer/importer_mesh_utils.cc + importer/obj_import_file_reader.cc + importer/obj_import_mesh.cc + importer/obj_import_mtl.cc + importer/obj_import_nurbs.cc + importer/obj_importer.cc + importer/parser_string_utils.cc IO_wavefront_obj.h exporter/obj_export_file_writer.hh @@ -36,6 +44,14 @@ set(SRC exporter/obj_export_mtl.hh exporter/obj_export_nurbs.hh exporter/obj_exporter.hh + importer/importer_mesh_utils.hh + importer/obj_import_file_reader.hh + importer/obj_import_mesh.hh + importer/obj_import_mtl.hh + importer/obj_import_nurbs.hh + importer/obj_import_objects.hh + importer/obj_importer.hh + importer/parser_string_utils.hh ) set(LIB @@ -53,6 +69,7 @@ blender_add_lib(bf_wavefront_obj "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") if(WITH_GTESTS) set(TEST_SRC tests/obj_exporter_tests.cc + tests/obj_importer_tests.cc tests/obj_exporter_tests.hh ) diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.cc b/source/blender/io/wavefront_obj/IO_wavefront_obj.cc index cebdf33413e..c80d10d9efd 100644 --- a/source/blender/io/wavefront_obj/IO_wavefront_obj.cc +++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.cc @@ -9,6 +9,7 @@ #include "IO_wavefront_obj.h" #include "obj_exporter.hh" +#include "obj_importer.hh" /** * C-interface for the exporter. @@ -18,3 +19,12 @@ void OBJ_export(bContext *C, const OBJExportParams *export_params) SCOPED_TIMER("OBJ export"); blender::io::obj::exporter_main(C, *export_params); } + +/** + * Time the full import process. + */ +void OBJ_import(bContext *C, const OBJImportParams *import_params) +{ + SCOPED_TIMER(__func__); + blender::io::obj::importer_main(C, *import_params); +} diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h index 289e37b3885..b80c1e073b8 100644 --- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h +++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h @@ -77,6 +77,17 @@ struct OBJExportParams { bool smooth_groups_bitflags; }; +struct OBJImportParams { + /** Full path to the source OBJ file to import. */ + char filepath[FILE_MAX]; + /** Value 0 disables clamping. */ + float clamp_size; + eTransformAxisForward forward_axis; + eTransformAxisUp up_axis; +}; + +void OBJ_import(bContext *C, const struct OBJImportParams *import_params); + void OBJ_export(bContext *C, const struct OBJExportParams *export_params); #ifdef __cplusplus diff --git a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc new file mode 100644 index 00000000000..7019e67419e --- /dev/null +++ b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup obj + */ + +#include "BKE_mesh.h" +#include "BKE_object.h" + +#include "BLI_delaunay_2d.h" +#include "BLI_math_vector.h" +#include "BLI_set.hh" + +#include "DNA_object_types.h" + +#include "IO_wavefront_obj.h" + +#include "importer_mesh_utils.hh" + +namespace blender::io::obj { + +Vector<Vector<int>> fixup_invalid_polygon(Span<float3> vertex_coords, + Span<int> face_vertex_indices) +{ + using namespace blender::meshintersect; + if (face_vertex_indices.size() < 3) { + return {}; + } + + /* Calculate face normal, to project verts to 2D. */ + float normal[3] = {0, 0, 0}; + float3 co_prev = vertex_coords[face_vertex_indices.last()]; + for (int idx : face_vertex_indices) { + BLI_assert(idx >= 0 && idx < vertex_coords.size()); + float3 co_curr = vertex_coords[idx]; + add_newell_cross_v3_v3v3(normal, co_prev, co_curr); + co_prev = co_curr; + } + if (UNLIKELY(normalize_v3(normal) == 0.0f)) { + normal[2] = 1.0f; + } + float axis_mat[3][3]; + axis_dominant_v3_to_m3(axis_mat, normal); + + /* Prepare data for CDT. */ + CDT_input<double> input; + input.vert.reinitialize(face_vertex_indices.size()); + input.face.reinitialize(1); + input.face[0].resize(face_vertex_indices.size()); + for (int64_t i = 0; i < face_vertex_indices.size(); ++i) { + input.face[0][i] = i; + } + input.epsilon = 1.0e-6f; + input.need_ids = true; + /* Project vertices to 2D. */ + for (size_t i = 0; i < face_vertex_indices.size(); ++i) { + int idx = face_vertex_indices[i]; + BLI_assert(idx >= 0 && idx < vertex_coords.size()); + float3 coord = vertex_coords[idx]; + float2 coord2d; + mul_v2_m3v3(coord2d, axis_mat, coord); + input.vert[i] = double2(coord2d.x, coord2d.y); + } + + CDT_result<double> res = delaunay_2d_calc(input, CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES); + + /* Emit new face information from CDT result. */ + Vector<Vector<int>> faces; + faces.reserve(res.face.size()); + for (const auto &f : res.face) { + Vector<int> face_verts; + face_verts.reserve(f.size()); + for (int64_t i = 0; i < f.size(); ++i) { + int idx = f[i]; + BLI_assert(idx >= 0 && idx < res.vert_orig.size()); + if (res.vert_orig[idx].is_empty()) { + /* If we have a whole new @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list [email protected] List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs
