Add texture projection frame overlay, fix remeshing and subdivision

This commit is contained in:
ExPikaPaka committed 2026-07-21 09:44:25 +02:00
1 parent 8247514ae2
commit ab023f3f6d
24 files changed
+4658 -120

No files matched your search

+46 -2
View File
@@ -29,6 +29,7 @@
// For parameterize_lscm()
#include <CGAL/Polygon_mesh_processing/border.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/Polygon_mesh_processing/detect_features.h>
#include <CGAL/Surface_mesh_parameterization/Error_code.h>
#include <CGAL/Surface_mesh_parameterization/LSCM_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/parameterize.h>
@@ -259,7 +260,8 @@ indexed_triangle_set cgal_to_indexed_triangle_set(const CGALMesh &cgalmesh)
// Isotropic remeshing
// /////////////////////////////////////////////////////////////////////////////
indexed_triangle_set remesh_isotropic(const indexed_triangle_set &mesh, double target_edge_length, unsigned n_iterations)
indexed_triangle_set remesh_isotropic(const indexed_triangle_set &mesh, double target_edge_length,
unsigned n_iterations, double sharp_angle_deg)
{
if (mesh.indices.empty() || target_edge_length <= 0.0)
return mesh;
@@ -269,14 +271,56 @@ indexed_triangle_set remesh_isotropic(const indexed_triangle_set &mesh, double t
if (cgal_mesh.is_empty() || cgal_mesh.number_of_faces() == 0)
return mesh;
// Surface_mesh::add_face() refuses any face that would make the mesh non-manifold and returns a
// null descriptor instead. Remeshing a mesh that silently lost faces that way produces holes in
// the output, so bail out and let the caller report it rather than hand back a punctured model.
if (cgal_mesh.number_of_faces() != mesh.indices.size())
return mesh;
using edge_descriptor = boost::graph_traits<_EpicMesh>::edge_descriptor;
try {
// Sharp edges and open borders are pinned before remeshing. Without that, the tangential
// relaxation pass slides vertices along the surface and rounds every hard feature off - a
// cube comes back with wobbly, eroded edges, which is the most visible way "remeshing does
// not work properly". protect_constraints() forbids splitting or collapsing them, but it
// requires each constrained edge to already be shorter than 4/3 * target, hence the split
// first (passing the map so the halves inherit the constraint). This mirrors CGAL's own
// isotropic_remeshing example.
auto ecm = cgal_mesh.add_property_map<edge_descriptor, bool>("e:is_constrained", false).first;
if (sharp_angle_deg > 0.0)
CGALProc::detect_sharp_edges(cgal_mesh, sharp_angle_deg, ecm);
for (edge_descriptor e : edges(cgal_mesh)) {
const auto h = halfedge(e, cgal_mesh);
if (is_border(h, cgal_mesh) || is_border(opposite(h, cgal_mesh), cgal_mesh))
put(ecm, e, true);
}
std::vector<edge_descriptor> constrained;
for (edge_descriptor e : edges(cgal_mesh))
if (get(ecm, e))
constrained.push_back(e);
if (!constrained.empty())
CGALProc::split_long_edges(constrained, target_edge_length, cgal_mesh,
CGALParams::edge_is_constrained_map(ecm));
CGALProc::isotropic_remeshing(faces(cgal_mesh), target_edge_length, cgal_mesh,
CGALParams::number_of_iterations(n_iterations));
CGALParams::number_of_iterations(n_iterations)
.edge_is_constrained_map(ecm)
.protect_constraints(true));
} catch (const std::exception &) {
return mesh; // CGAL throws on some non-manifold / degenerate inputs; leave the mesh untouched
}
if (cgal_mesh.number_of_faces() == 0)
return mesh;
// isotropic_remeshing edits in place, and its edge collapses only *mark* vertices and faces as
// removed - the underlying arrays keep the holes until the garbage is collected. That matters
// because cgal_to_indexed_triangle_set() numbers its output vertices by iteration order (which
// skips removed slots) while reading each face's corner as the raw integer value of the vertex
// descriptor (which does not). Past the first collapse the two disagree, so every triangle
// points at the wrong vertices, and any descriptor beyond the live vertex count is dropped
// together with its triangle. Compacting first makes descriptor == iteration order again.
cgal_mesh.collect_garbage();
return cgal_to_indexed_triangle_set(cgal_mesh);
}