#include #include #include #include #include void export_halfpatch_obj( const stl_vector_mp& iso_pts, const stl_vector_mp& iso_faces, const stl_vector_mp>& patches, const std::string& filename) { std::string mtl_filename = filename + ".mtl"; std::ofstream mtl(mtl_filename); for (size_t half_patch = 0; half_patch < patches.size() * 2; ++half_patch) { size_t patch_idx = half_patch / 2; bool is_forward = (half_patch % 2 == 0); mtl << "newmtl patch_" << patch_idx << (is_forward ? "_in" : "_out") << "\n"; // 随机或规律分配颜色 float r = float(patch_idx % 7) / 7.0f; float g = float(patch_idx % 3) / 3.0f; float b = float(patch_idx % 5) / 5.0f; mtl << "Kd " << r << " " << g << " " << b << "\n"; } mtl.close(); std::string obj_filename = filename + ".obj"; std::ofstream ofs(obj_filename); if (!ofs) return; ofs << "mtllib "<< mtl_filename << "\n"; // 输出所有顶点 for (const auto& v : iso_pts) { ofs << "v " << v.x() << " " << v.y() << " " << v.z() << "\n"; } // 遍历所有 half-patch for (size_t half_patch = 0; half_patch < patches.size() * 2; ++half_patch) { size_t patch_idx = half_patch / 2; bool is_forward = (half_patch % 2 == 0); ofs << "g halfpatch_" << half_patch << "\n"; ofs << "usemtl patch_" << patch_idx << (is_forward ? "_in" : "_out") << "\n"; for (auto face_idx : patches[patch_idx]) { const auto& face = iso_faces[face_idx]; ofs << "f"; if (is_forward) { for (auto vi : face.vertex_indices) ofs << " " << (vi + 1); } else { for (auto it = face.vertex_indices.rbegin(); it != face.vertex_indices.rend(); ++it) ofs << " " << (*it + 1); } ofs << "\n"; } } ofs.close(); } ISNP_API void build_implicit_network_by_blobtree(const s_settings& settings, const baked_blobtree_t& tree, stl_vector_mp& output_vertices, stl_vector_mp& output_polygon_faces, stl_vector_mp& output_vertex_counts_of_face) { // load LUT for implicit arrangement load_lut(); scene_bg_mesh_info_t scene_bg_mesh_info{}; stl_vector_mp> tetrahedrons{}; flat_hash_map_mp vertex_lexigraphical_adjacency{}; stl_vector_mp tetrahedron_active_subface_start_index{}; stl_vector_mp active_subface_indices{}; stl_vector_mp tetrahedron_arrangements{}; flat_hash_map_mp> zero_vertex_to_incident_tet_mapping{}; stl_vector_mp iso_pts{}; stl_vector_mp iso_verts{}; stl_vector_mp iso_faces{}; // primitive generation { Eigen::MatrixXd vertex_infos = Eigen::MatrixXd::Zero((settings.resolution + 1) * (settings.resolution + 1) * (settings.resolution + 1), tree.subfaces.size()); flat_hash_map_mp vertex_indices_mapping{}; { btree_map_mp> vertex_to_tet_mapping{}; flat_hash_map_mp> reverse_vertex_adjacency{}; { stl_vector_mp vertex_exist_regions{}; extract_vertex_infos(settings, tree, scene_bg_mesh_info, vertex_infos); build_tetrahedron_and_adjacency(scene_bg_mesh_info, tetrahedrons, vertex_lexigraphical_adjacency, reverse_vertex_adjacency, vertex_to_tet_mapping); } filter_tet_by_subface(vertex_to_tet_mapping, vertex_infos, vertex_indices_mapping, tetrahedrons, vertex_lexigraphical_adjacency, reverse_vertex_adjacency, tetrahedron_active_subface_start_index, active_subface_indices, zero_vertex_to_incident_tet_mapping); } auto tet_active_subface_counts = compute_implicit_arrangements(vertex_infos, vertex_indices_mapping, tetrahedrons, tetrahedron_active_subface_start_index, active_subface_indices, tetrahedron_arrangements); extract_iso_mesh(tet_active_subface_counts, tetrahedron_arrangements, scene_bg_mesh_info, tetrahedrons, tetrahedron_active_subface_start_index, active_subface_indices, vertex_infos, vertex_indices_mapping, iso_pts, iso_verts, iso_faces); } // connect components by topology stl_vector_mp patch_of_face(iso_faces.size()); stl_vector_mp shell_of_half_patch{}; stl_vector_mp component_of_patch{}; stl_vector_mp> patches{}; stl_vector_mp> chains{}; stl_vector_mp> shells{}; stl_vector_mp> components{}; stl_vector_mp> arrangement_cells{}; stl_vector_mp shell_to_cell{}; { { stl_vector_mp> edges_of_iso_face{}; stl_vector_mp iso_edges{}; compute_patch_edges(iso_faces, edges_of_iso_face, iso_edges); compute_patches(edges_of_iso_face, iso_edges, iso_faces, patches, patch_of_face); compute_chains(iso_verts.size(), iso_edges, chains); export_halfpatch_obj(iso_pts, iso_faces, patches, "halfpatch_before_connect"); } stl_vector_mp> half_patch_adj_list(2 * patches.size()); for (size_t i = 0; i < chains.size(); ++i) compute_patch_order(tetrahedrons, chains[i].front(), iso_verts, iso_faces, tetrahedron_arrangements, tetrahedron_active_subface_start_index, active_subface_indices, zero_vertex_to_incident_tet_mapping, patch_of_face, half_patch_adj_list); compute_shells_and_components(half_patch_adj_list, shells, shell_of_half_patch, components, component_of_patch); if (components.size() == 1) // no nesting problem, each shell is an arrangement cell { arrangement_cells.reserve(shells.size()); for (uint32_t i = 0; i < shells.size(); ++i) { arrangement_cells.emplace_back(stl_vector_mp{i}); } } else { { stl_vector_mp> shell_links{}; topo_ray_shooting(scene_bg_mesh_info, tetrahedrons, vertex_lexigraphical_adjacency, tetrahedron_arrangements, iso_verts, iso_faces, patches, patch_of_face, shells, shell_of_half_patch, components, component_of_patch, shell_links); compute_arrangement_cells(static_cast(shells.size()), shell_links, arrangement_cells); } } shell_to_cell.resize(shells.size()); for (uint32_t i = 0; i < arrangement_cells.size(); i++) { for (auto shell : arrangement_cells[i]) shell_to_cell[shell] = i; } // post process { dynamic_bitset_mp<> active_cell_label{}; { stl_vector_mp> cell_primitive_signs(tree.primitives.size(), dynamic_bitset_mp<>(arrangement_cells.size())); { stl_vector_mp> cell_subface_signs(tree.subfaces.size(), dynamic_bitset_mp<>(arrangement_cells.size())); propagate_subface_labels(tree, iso_faces, patches, arrangement_cells, shell_of_half_patch, shells, shell_to_cell, cell_subface_signs); transform_subface_to_primitive_labels(tree, cell_subface_signs, cell_primitive_signs); } active_cell_label = filter_cells_by_boolean(tree, cell_primitive_signs); } filter_polygon_faces(iso_faces, patches, arrangement_cells, shell_of_half_patch, shells, shell_to_cell, active_cell_label, output_polygon_faces, output_vertex_counts_of_face); filter_active_vertices(output_vertices, output_polygon_faces); export_halfpatch_obj(iso_pts, iso_faces, patches, "halfpatch_final"); } } }