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 9aeb0b7ab58..3fed4547cf2 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -89,7 +89,7 @@ void OBJMesh::clear() owned_export_mesh_ = nullptr; } export_mesh_ = nullptr; - uv_indices_.clear_and_shrink(); + loop_to_uv_index_.clear_and_shrink(); uv_coords_.clear_and_shrink(); loop_to_normal_index_.clear_and_shrink(); normal_coords_.clear_and_shrink(); @@ -162,7 +162,7 @@ int OBJMesh::tot_polygons() const int OBJMesh::tot_uv_vertices() const { - return tot_uv_vertices_; + return int(uv_coords_.size()); } int OBJMesh::tot_edges() const @@ -290,71 +290,47 @@ Span OBJMesh::calc_poly_vertex_indices(const int poly_index) const void OBJMesh::store_uv_coords_and_indices() { - const int totvert = export_mesh_->totvert; const StringRef active_uv_name = CustomData_get_active_layer_name(&export_mesh_->ldata, CD_PROP_FLOAT2); if (active_uv_name.is_empty()) { - tot_uv_vertices_ = 0; + uv_coords_.clear(); return; } const bke::AttributeAccessor attributes = export_mesh_->attributes(); const VArraySpan uv_map = attributes.lookup(active_uv_name, ATTR_DOMAIN_CORNER); if (uv_map.is_empty()) { - tot_uv_vertices_ = 0; + uv_coords_.clear(); return; } - const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT}; + Map uv_to_index; - UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create( - mesh_polys_.data(), - nullptr, - nullptr, - mesh_corner_verts_.data(), - reinterpret_cast(uv_map.data()), - mesh_polys_.size(), - totvert, - limit, - false, - false); + /* We don't know how many unique UVs there will be, but this is a guess. */ + uv_to_index.reserve(export_mesh_->totvert); + uv_coords_.reserve(export_mesh_->totvert); - uv_indices_.resize(mesh_polys_.size()); - /* At least total vertices of a mesh will be present in its texture map. So - * reserve minimum space early. */ - uv_coords_.reserve(totvert); + loop_to_uv_index_.resize(uv_map.size()); - tot_uv_vertices_ = 0; - for (int vertex_index = 0; vertex_index < totvert; vertex_index++) { - const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, vertex_index); - for (; uv_vert; uv_vert = uv_vert->next) { - if (uv_vert->separate) { - tot_uv_vertices_ += 1; - } - const int verts_in_poly = mesh_polys_[uv_vert->poly_index].totloop; - - /* Store UV vertex coordinates. */ - uv_coords_.resize(tot_uv_vertices_); - const int loopstart = mesh_polys_[uv_vert->poly_index].loopstart; - Span vert_uv_coords(uv_map[loopstart + uv_vert->loop_of_poly_index], 2); - uv_coords_[tot_uv_vertices_ - 1] = float2(vert_uv_coords[0], vert_uv_coords[1]); - - /* Store UV vertex indices. */ - uv_indices_[uv_vert->poly_index].resize(verts_in_poly); - /* Keep indices zero-based and let the writer handle the "+ 1" as per OBJ spec. */ - uv_indices_[uv_vert->poly_index][uv_vert->loop_of_poly_index] = tot_uv_vertices_ - 1; + for (int index = 0; index < int(uv_map.size()); index++) { + float2 uv = uv_map[index]; + int uv_index = uv_to_index.lookup_default(uv, -1); + if (uv_index == -1) { + uv_index = uv_to_index.size(); + uv_to_index.add(uv, uv_index); + uv_coords_.append(uv); } + loop_to_uv_index_[index] = uv_index; } - BKE_mesh_uv_vert_map_free(uv_vert_map); } Span OBJMesh::calc_poly_uv_indices(const int poly_index) const { - if (uv_indices_.size() <= 0) { + if (uv_coords_.is_empty()) { return {}; } BLI_assert(poly_index < export_mesh_->totpoly); - BLI_assert(poly_index < uv_indices_.size()); - return uv_indices_[poly_index]; + const MPoly &poly = mesh_polys_[poly_index]; + return loop_to_uv_index_.as_span().slice(poly.loopstart, poly.totloop); } float3 OBJMesh::calc_poly_normal(const int poly_index) 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 a90f6e3c3fd..b19c5df740f 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh @@ -52,17 +52,14 @@ class OBJMesh : NonCopyable { bool mirrored_transform_; /** - * Total UV vertices in a mesh's texture map. + * Per-loop UV index. */ - int tot_uv_vertices_ = 0; - /** - * Per-polygon-per-vertex UV vertex indices. - */ - Vector> uv_indices_; + Vector loop_to_uv_index_; /* * UV vertices. */ Vector uv_coords_; + /** * Per-loop normal index. */ diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc index 5be3bf781ac..8308250510b 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -340,6 +340,19 @@ TEST_F(obj_exporter_regression_test, edges) } TEST_F(obj_exporter_regression_test, vertices) +{ + OBJExportParamsDefault _export; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; + _export.params.export_materials = false; + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR + "cube_loose_edges_verts.blend", + "io_tests" SEP_STR "obj" SEP_STR "cube_loose_edges_verts.obj", + "", + _export.params); +} + +TEST_F(obj_exporter_regression_test, cube_loose_edges) { OBJExportParamsDefault _export; _export.params.forward_axis = IO_AXIS_Y;