0

在我的应用程序中,我使用了很多三角形网格,有时我需要减少其中的三角形数量(折叠一些边)。对于网格处理,我使用 openmesh (openmesh.org),因为它是现代的 (C++),但主要是因为它不会拖累大量依赖项(仅依赖于 c++ std 并且任何现代编译器都可以处理它(我需要跨平台) Linux/Windows/Mac OSX))。

现在我需要减少(openmesh 术语中的抽取)一些网格,但我需要保留边界。(有问题的网格是原始网格(512x512),但在它们的中心,一些凹面元素被挤出/添加,关键是在缩小后网格的外边缘仍然形成矩形)

我看不到任何方法可以在 openmesh 中抽取它们并保留体积/轮廓,所有 OpenMesh::Decimater::Mod* 抽取模块都使用二次作为其基础。

在 GTS(GNU Triangulated Surface Library)中,实现了 Lindstrom-Turk 缩减,非常适合我的需求(我做了一些肮脏的包装来测试它是否是我想要的)并且它可以工作,但是 GTS 存在问题 - 它是不是多线程保存(我在多个线程上减少了许多网格)并且使用 GTS 是不可能的,因为它使用库中的全局变量来禁用/启用某些东西,同时减少网格:/)(而且它也拖了整个 glib,因为它是依赖项)

还有 CGAL,它也实现了 Lindstrom-Turk,但它本身拖了整个 boost 和其他依赖项:/

是否有任何用于 openmesh 的抽取器模块可以通过边界/体积保留进行抽取?(我已经搜索过,但没有找到:/)

4

1 回答 1

1

据我了解,“网格边界”是指仅形成单个网格面的网格边缘(如示例中的 512x512 网格的外边缘),而不是更常见的情况,即每个网格边缘在 2或更多网格面。

在 OpenMesh 中,实际上有一种非常简单的方法可以告诉OpenMesh::Decimater模块按原样保留这些边缘。更好的是,它不依赖于您实际使用的抽取模块的类型。实际的网格数据结构(即OpenMesh::TriMesh_ArrayKernelT<>)具有称为“顶点锁定”的特性。它本质上是一种告诉 OpenMesh 在抽取期间无论如何都不要接触特定顶点集的方法。

这是直接来自官方文档的代码片段,针对 C++11 做了一些改动:

using Mesh = OpenMesh::TriMesh_ArrayKernelT<>;

void protectMeshBoundariesFromDecimation(Mesh& mesh) {
   mesh.request_vertex_status();

   for (const auto& halfEdgeHandle : mesh.halfedges()) {
      if (mesh.is_boundary(halfEdgeHandle) ) {
         mesh.status(mesh.to_vertex_handle(halfEdgeHandle)).set_locked(true);
         mesh.status(mesh.from_vertex_handle(halfEdgeHandle)).set_locked(true);
      }
   }
}

如果您想阅读有关该问题的完整文档并且上面的链接不再起作用,请在文档内容树中转到OpenMesh -> OpenMesh Documentation -> OpenMesh Tools Documentation -> Mesh Decimation Framework

本质上,这会在网格的所有半边(不是边!)上循环,并“锁定”形成没有对的半边(没有第二个半边)的顶点。由于 OpenMesh 使用的半边数据结构的性质,这O(n)对于边的网格来说具有复杂性n

如果您不熟悉半边数据结构的细节,我建议您通读 OpenMesh 文档中出色的“使用和理解 OpenMesh”介绍部分。

于 2015-10-18T15:38:51.110 回答