详细解读!Isotropic Remeshing的详细介绍与实现

学习remeshing,今天看了知乎大佬的一篇文章,给大家共同总结学习一下,真的不错。

1. 问题

对于三角网格,可能顶点分布不均,这会影响很多网格应用的效果(如数值模拟,几何建模等),因此需要将网格均匀化。示例如下,(左)分布不均(右)均匀分布

 

所谓均匀的网格,最简单的度量是

  • 所有边等长
  • 所有三角形面积相等
  • 所有顶点度数为 6

2. 算法

本文介绍的算法是 [Botsch and Kobbelt 04b][1][2] 提出的,特点是实现简单,鲁棒性好,而且效果也好。伪代码如下

remesh(target_edge_length)
  low = 4/5 * target_edge_length
  high = 4/3 * target_edge_length
  for i = 0 to 10 do
    spilt_long_edges(high)
    collapse_short_edges(low, high)
    equalize_valences()
    tangential_relaxation()
    project_to_surface()

其中target_edge_length是网格的目标长度,可取为原网格M的平均长度 ,其中E(M)是网格的边集

2.1网格局部操作

本算法涉及三个局部操作,如下

在用半边结构时,算法实现简单但繁琐,Edge Spilt 和 Edge Flip 没什么坑,注意判断网格边界即可。Edge Collapse 比较坑,在部分情况下会不合法[3],如下(产生了二度点和重边,不再是三角网格)

Edge Collapse 不合法情形

合法时的判断条件为,其中 是边的两个端点

2.2 Spilt Long Edges

该步骤将所有长于high = 4/3 * target_edge_length的边进行 Edge Spilt 操作,新增的点位置为边两端点的中点。伪代码如下

spilt_long_edges(high)
  while exists edge e with length(e) > high do
    spilt e at midpoint(e)

对于具体实现,关键在于边的遍历,特别注意 Edge Spilt 后会新增 4 条边,C++ 实现如下

unordered_set<E*> edges = mesh->Edges();
while(!edges.empty()){
  auto iter = edges.begin();
  E* e = *iter;
  edges.erase(iter);
  if(e->Length() > high){
    V* v = mesh->SpiltEdge(e, e->Centroid());
    for(E* adjE : v->AdjEdges()) // add adjacent edges of new vertex v
      edges.push_back(adjE);
  }
}

2.3 Collapse Short Edges

该步骤将所有短于low = 4/5 * target_edge_length的边进行 Edge Collapse 操作,新增的点位置为边两端点的中点,另外要求新的边不会长于high = 4/3 * target_edge_length。伪代码如下

collapse_short_edges(low, high)
  while exists unchecked edge e with length(e) < low do
    if collapse e will make some edges longer than high
      continue
    collapse e at midpoint(e)

对于具体实现,关键在于边的遍历,特别注意 Edge Collapse 后相邻边的长度会发生改变,需要重新考虑。此外 Edge Collapse 会有不合法的情形。对于有边界的网格,一般要求边界不动,边两顶点不能是边界点。另外,如果边两顶点的邻点是边界点的话,collapse 后会导致新点度数增加(有大量的邻接点是边界点),因而也要求边两点的邻点没有边界点。

C++ 实现如下

unordered_set<E*> edges(mesh->Edges().begin(), mesh->Edges().end());
while(!edges.empty()){
  auto iter = edges.begin();
  E* e = *iter;
  edges.erase(iter);
  
  if(!e->IsCanCollapse(minL, maxL)) // test lots of contidons
    continue;
  
  vector<E*> eAdjEs = e->AdjEdges();
  if(eAdjEs.size() <= 2)
    continue; // dihedron
  
  V* v = mesh->CollapseEdge(e, c);
  if(v){ // collapse e success
    for(E* eAdjE : eAdjEs)
      edges,erase(eAdjE); // erase old edges
    for(E* adjE : v->AdjEdges())
      edges.insert(adjE); // add new edges
  }
}

2.4 Equalize Valences

该步骤目的是平衡顶点的度数,最佳度数 optimal valence 为

  • 内部点:6
  • 边界点:4

如果 Edge Flip 能减少与最佳度数的差,则进行 Edge Flip,伪代码如下

equalize_valences()
  for each edge e do
    if flip e can reduce valence excess do
      flip(e)

Edge Flip 会导致边原两端点度数减 1,新两端点度数加 1

这里有坑

  • 对于三角网格,除了边界点度数可为 2,内部点度数都在 3 及以上,故若 Edge Flip 会产生 2 度内部点时不合法
  • 边界边不可进行 Edge Flip 操作
  • 对于凹四边形,flip 后会导致逆向的面

凹四边形

C++ 实现如下

vector<E*> edges = mesh->Edges();
for(E* e : edges){
  if(e->IsBoundary())
    continue;
  int valenceExcess = /*...omit calulate ...*/;
  int flipedValenceExcess = /*...omit calulate ...*/;
  if(flipedValenceExcess >= valenceExcess)
    continue;
  if(/*non convex polygon*/)
    continue;
  flip(e);
}

2.5 Tangential Relaxation 和 Project to Surface

2.2 节和 2.3 节解决了边的长度问题,2.4 节解决了顶点度数问题,本节步骤解决的是三角形面积问题。

简单来说,将顶点向中心(邻接点的平均 ,其中  是顶点 的邻接点集, 是 的位置)平移即可,如下所示

我实现时采用了重力加权中心 gravity-weighted centroid[1],如下

其中  所在的两三角形的面积均值(对于边界点 ,只有一个三角形)

另外平移时为了能保持原有网格的形状,且防止抖动,需要在切向进行平移,并且投影回原网格上,示例如下[4]

平移量为 ,切向平移为(其中 是  的法向),从而得到未投影的点位置

顶点法向可用顶点周围三角形法向的带权平均,权值为面积,公式如下

其中  是  的邻接三角形集,  是三角形  的面积,  是  的法向

最后需要将点沿着法向投影回原网格上,点和法向构成的射线与  相交,涉及相交算法。

边界点不动。

3. 其他问题

3.1 二面体

算法可能在 Collapse Edge 后引入二面体(三个点,两个面,顺序相反)

此时应及时停止算法

3.2 并行

网格局部操作可以并行,但在进行操作时需要进行必要的锁资源。简单上锁整个网格就没法并行了,我采取的方案是锁相关顶点,比如 Edge Flip 需要锁住四个顶点。注意再加锁过程中可能有其他线程修改了邻接关系,导致锁点错误,因此需在最后检测所锁点是否仍为邻接点。因此并行的 overhead 比较大,效果不是很明显。

暂时只实现了 Edge Flip 的并行,日后会继续探究 Edge Spilt 和 Edge Collapse 的并行策略。

3.3 形状

2.5 节通过切向平移和投影一定程度上保持了网格形状,但还是会有轻微变化,在实际使用时,会人为指定特征点、边,算法中 Edge Flip、Edge Collapse 等要求不修改特征点、边,如此可进一步保持形状,较为繁杂,本文忽略。

4. 性能

CPU:Intel(R) Pentium(R) Gold G5400 CPU @ 3.70GHz

50, 000 顶点,100, 000 面的网格

进行 5 次循环,耗时 13s 左右

5. 测试

原网格

处理后网格

网格变均匀了,每个三角形大致都是等边三角形,且面积都挺小

另外,正如 3.3 节所述,部分区域的形状并没有很好保持住,主要就是一些特征边(龙尾,龙背等),大部分区域形状是保持的。

 

参考

  1. ^abBotsch M , Kobbelt L . A Remeshing Approach to Multiresolution Modeling[C]// Second Eurographics Symposium on Geometry Processing, Nice, France, July 8-10, 2004. 2004. http://www.graphics.rwth-aachen.de/media/papers/remeshing1.pdf
  2. ^Botsch M, Kobbelt L, Pauly M, et al. Polygon mesh processing[M]. AK Peters/CRC Press, 2010.
  3. ^UTD. 3D Geometric Modeling. https://personal.utdallas.edu/~praba/6v81/3dModeling.pdf
  4. ^CS468. Stanford Computer Graphics Laboratory. Remeshing I. http://graphics.stanford.edu/courses/cs468-12-spring/LectureSlides/13_Remeshing1.pdf
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水木流年追梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值