网格(mesh)简化

(一)全都是占位点惹的祸

我已经耗费了好几天简化地图-感觉上我似乎会阶段性地遇到这个问题。在重新简化的过程中,我意识到这个问题说起来比我想象中的会简单

在一个给定范围(也就是,一个线段的集合和既不是线段交点也不是线段的端点的自由点)内我们可以迭代地用一条“捷径”线段替代邻近的线段进行简化(例如:用线段pr代替pq和qr线段)并且给定条件如下:

顶点的度q为2(例如:只有pq和qr有点q)。

线段pr不在集合范围内。

三角形pqr(不是位于p和r之间)。按照定义来说pq和qr上没有其他的点。

测试3——对于占位点(也就是在三角形PQR内或其边上的点)测试——是关键。如果PQR内有多余的点,那么就会产生一些岛型几何图形(或自由顶点)并且再简化之后就会出现在pqr不正确的那边,或者,几何图形与pr外的部分“连接”且pr会与图中线段相交。这两种情况下都不应该对网格进行简化。

鉴于此,我们可以构建一个迭代算法简化网格:把每个通过这些测试的基础后的顶点放到一个队列,测试基于移除该点会导致错误的原理。移除第一个顶点,基于变化的误差度量重新排列相邻顶点。请注意,如果其中的"占位点"从测试3此前已移除,一个以前被"困"的顶点现在可能是可移除的了。


该区域不是我们想要的
通过计算区域此前我已编码类似的逻辑,——即找到每一个和pr相交的点、线、面。这有几个问题: 规划区域的计算的代价是很高的。给出了一个X条边的简单多边形,我们就必须要做X区计算一样多的计算(如果任一顶点的移除都是合法的)和区域还要迭代计算多边形边界。因此,我们有一个O(N^2)计算,一个由大量较小的编组成的巨大多边形的计算是相当痛苦的工作。(悲剧的是,这正是我此前数据的样子。 )这样做区域计算是错误的,即便我们的程序没有崩溃,如果区域内有洞在三角形PQR 中,那么我们还是不应该去简化。因此,在进行区域计算的同时要迭代绕过洞。

二、规划简化


Mesh Simplification Part II - Arrangement Simplification
In my previous post, I suggested that we can iteratively simplify an arrangement if we can test a node's degree, the pre-existence of the simplifying edge we want to replace it with, and confirm that there are no "squatting" vertices inside the triangle formed by the two old edges and the one new one.


To simplify an arrangement, therefore, what we really need is a good spatial index to make searching for squatters fast.


Previously I had used a quadtree-like structure, but I seem to be getting better results using a Delaunay triangulation. (This idea is based on the CGAL point_set_2 class).
We insert every vertex of our arrangement into a Delaunay triangulation.
When we want to check for squatters, we find the minimum circle enclosing the triangle pqr (where pqr is the curve pair we want to simplify to pr) and search the triangulation for nodes inside the circle.
To search the Delaunay triangulation for nodes within a fixed distance of point P, we first insert P (if it isn't already present) and then do a search (depth or breadth-search) from P outward based on vertex adjacency. When done, we remove P if it wasn't already part of the triangulation.


Implementation Details


For my implementation using arrangements, there are a few quirks:
I use my own point set; CGAL's point set uses a stack-based depth-first search that tends to flood the stack for large data sets.
I do not re-queue previously "blocked" points as squatters are removed. This would be a nice feature to add at some point (but is not easily added with a mere index).
I abuse CGAL's "merge_edge" routine to do the simplification. Edge merge was meant for collinear curves; in my case I pre-ensure that it is a safe operation. The advantage of using merge_edge vs. actually inserting the new edges and removing the old ones is speed and stability: no faces are created or removed, thus face data stays stable, and no geometry tests are needed to determine what holes go in what face, etc.
Because I am edge-merging, I can't merge two edges that have opposite x-monotone "direction" - thus some details won't get simplified. This is a limitation of CGAL's arrangement interface.
Here's why the last point happens: CGAL caches the "direction" (left to right or right to left) of its X-Monotone curves on the half-edge itself. Since merge assumes that we aren't moving the point-set that is the curve, but rather glue-ing two curves together in-place, it assumes that the merged half-edge direction cannot have changed. Thus it does not recalculate the direction flag.


Since the method recycles two of the four half-edges in the merge, if the first half of the curve points in the opposite direction of the merged curve, the merge is changing the half-edge's direction.


Could this case happen if the merged edge had the same path as the original two edges? No. In order for the direction to change, the two underlying curves cannot be summed to a single curve that is still x-monotone, which is a requirement for CGAL's arrangement.




三、简化三角剖分

Mesh Simplification Part III - Simplifying A Triangulation
Previously I suggested using a Delaunay triangulation as a spatial index to find "squatters" when simplifying an arrangement. If we want to simplify a triangulation itself, then the triangulation is the spatial index.


Consider a constrained Delaunay triangulation, where our arrangement edges have been replaced with triangulation constraints, and there are no free vertices (nor are there vertices in the triangulation that don't have at least one incident constraint).


We can now use an idea from the previously referenced paper: given a pair of constraints forming a curve pqr that we want to simplify into pr, if there exist any vertices that might be on the edge or in the interior of triangle pqr, then they must be adjacent to q in the triangulation (and between pq and pr on the accute side of pqr).


This means that we can simply circulate vertex q to search for squatters. The triangulation is the index.


Why does this work? Well, consider the case where there exists a vertex X inside triangle PQR that is not adjacent to Q. You can't have free vertices in a triangulation; the act of triangulating out X is going to create at least one link between Q and X; the only way that this will not happen is if there is already some other point inside PQR that is closer to Q than X (and in that case, we fail for that other point).


The triangulation also has the nice property that when we remove a vertex X, we can reconsider its adjacent vertices to see if X was a squatter of those other vertices. This works because if X is a squatter of Q and there are no other squatters (thus removing X "unlocks" Q) then X and Q must be connected.


Implementation Notes


In my case I have one other implementation consideration besides the usual requirements: in my case, I have a many-to-many link between vertices in my original arrangement and vertices in my triangulation. Some triangulation vertices will not have original nodes because they represent subdivision of the triangulation to improve elevation data. And some original arrangement vertices will not be in the triangulation due to simplification of the triangulation's constraints.


The problem is: how do we work backward from a triangulation triangle to an original arrangement face? Given a triangle with a constraint on one side, we need to figure out what arrangement halfedge(s) it links to.


In order to keep this "back-link" unambiguous, we cannot remove all of the degree 2 vertices from a poly-line of original edge segments. We need to leave at least one "poly-line interior" vertex in place to disambiguate two paths between vertices in the arrangement. (This case happens a lot when we have closed loops.)


In practice, we could never remove the poly-line interior vertices from all paths anyway (because they would collapse to zero paths) but in practice, we don't want to remove them from any poly-line because it makes resolving the original arrangement face more difficult.






  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Open3D提供了两种方法来实现网格简化:simplify_vertex_clustering和subdivide_midpoint。simplify_vertex_clustering是一种基于顶点聚类的方法,它将高分辨率的网格以更少的顶点和面表示出来。这个方法会根据指定的聚类参数将相似的顶点合并在一起,从而减少网格的复杂性。 另一种方法是subdivide_midpoint,它是一种网格细分的方法,可以将每个三角形网格划分成更多的小三角形网格。具体来说,它将每条边的中点计算出来并进行切分,从而得到更多的小三角形网格。这种方法能够保持网格表面和面积不变,但会增加网格的数量和顶点数目。这个方法在Open3D中通过subdivide_midpoint函数实现,你可以通过指定number_of_iterations参数来控制迭代的次数。 以下是一个使用Open3D进行网格简化的示例代码: ```python import open3d as o3d # 读取网格文件 mesh = o3d.io.read_triangle_mesh("input_mesh.obj") # 网格简化 mesh = mesh.simplify_vertex_clustering(1000) # 使用simplify_vertex_clustering方法,将网格简化为1000个顶点 # 保存简化后的网格 o3d.io.write_triangle_mesh("output_mesh.obj", mesh) ``` 上述代码中,我们首先使用`read_triangle_mesh()`函数读取输入的网格文件。然后,我们使用`simplify_vertex_clustering()`方法对网格进行简化,将网格的顶点数目减少到1000。最后,我们使用`write_triangle_mesh()`函数将简化后的网格保存为文件。 希望这个回答对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值