注意:说明比预期的要长一点。您是否知道使用此网格的可读实现此算法?请告诉我!
我正在尝试使用Matlab实现Catmull-Clark subdivision,因为稍后必须将结果与已在Matlab中实现的其他内容进行比较。首先尝试使用Vertex-Face网格,算法可以工作,但效率不高,因为边缘和面需要相邻信息。因此,我现在正在使用half-edge mesh。也可以看看 Designing a Data Structure for Polyhedral Surfaces, by Lutz Kettner(该页面上的PDF链接)。
我的问题在于找到 Twin HalfEdges ,我只是不确定如何做到这一点。下面我将描述我对实现的看法,试着保持简洁。
半边网格(使用Vertices / HalfEdges / Faces的索引):
Vertex (x,y,z,Outgoing_HalfEdge)
HalfEdge (HeadVertex (or TailVertex, which one should I use), Next, Face, Twin).
Face (HalfEdge)
为了保持现在的简单,假设每张脸都是四边形。实际网格是Vertices,HalfEdges和Faces的列表。新网格将由NewVertices,NewHalfEdges和NewFaces组成,如下所示(注意:数字_... 是 ... 的数量):
NumberNewVertices: Number_Faces + Number_HalfEdges/2 + Number_Vertices
NumberNewHalfEdges: 4 * 4 * NumberFaces
NumberNewfaces: 4 * NumberFaces
的Catmull-Clark的:
Find the FacePoint (centroid) of each Face:
--> Just average the x,y,z values of the vertices, save as a NewVertex.
Find the EdgePoint of each HalfEdge:
--> To prevent duplicates (each HalfEdge has a Twin which would result in the same HalfEdge)
--> Only calculate EdgePoints of the HalfEdge which has the lowest index of the Pair.
Update old Vertices
好的,现在计算了所有新的顶点(但是, Outgoing_HalfEdge 仍然未知)。下一步保存新的HalfEdges和Faces。 这是导致我出现问题的部分!
Loop through each old Face, there are 4 new Faces to be created
(because of the quadrilateral assumption)
First create the 4 new HalfEdges per New Face, starting at the FacePoint to the Edgepoint
Next a new HalfEdge from the EdgePoint to an Updated Vertex
Another new one from the Updated Vertex to the next EdgePoint
Finally the fourth new HalfEdge from the EdgePoint back to the FacePoint.
每个新的HalfEdge的 HeadVertex 都是众所周知的, Next HalfEdge 也是如此。 Face 也是众所周知的(因为它是您正在创建的新面孔!)。只有 Twin HalfEdge 未知,我应该怎么知道?
顺便说一下,在循环新面孔的顶点时,将 Outgoing_HalfEdge 指定给顶点。这可能是找出哪个HalfEdge是Twin的地方。
最后,在创建4个新的HalfEdges之后,使用 HalfVertex 索引保存Face最后新创建的HalfVertex。
我希望这很清楚,如果需要,我可以发布我的(显然尚未完成的)Matlab代码。
编辑:感谢您移动我的帖子。我在评论中发布了源代码的链接,请注意这个实现考虑了一般的多边形网格,所以不仅仅是四边形网格。
此外,如果您考虑将旧的四边形脸分为4个新脸(绿色数字),则新的HalfEdges 1和4的双胞胎(每个新脸中的红色数字)相当容易找到:
那么,如何找到2和3 HalfEdges的 Twins ?
答案 0 :(得分:1)
看起来你遇到的概念问题是你试图一次添加一个半边,然后想知道它们是如何加起来的。但是,边缘是真正的修改单位,所以你应该总是成对添加它们。
为了实现算法的(单次传递),我将使用“新创建”标志来注释每个模型元素,该标志指示元素是否是作为算法的结果而创建的。顶级循环将迭代未修改的面。
首先确保已分割脸部的每个原始边缘。在执行此操作时,为面部创建每个“新”顶点的列表;这些是中点。 - 一个。要分割边缘,我们首先找到相应的半边。创建一个新的顶点。我们在每个链表中插入一对新的半边,将端点调整到新的顶点。将所有四个半边标记为新的顶点和新顶点。
细分脸部的第一站与其他人不同。创建一个新的顶点V
,使其位于旧面的中间,并选择一个新的顶点W
事件到面部。我们将按如下方式连接它们。假设W
附近的链接列表看起来像..aWb..
。创建一对新的半边c
和d
。将链接列表中的W
替换为WcVdW
,以使列表'..aWcVdWb ..'。这会在脸部中间形成“浮动边缘”。但是,数据结构确保我们有一个半边的链表,表示多边形的内周长。将顶点W
和半边c
和d
标记为新的。
现在,对于每个剩余的新顶点,我们将创建一对新的半边,但这次每对还将创建一个新的面。选择上一个..cVdWb..
链接列表序列。由于所有原始边缘都已细分,因此该列表会扩展到..cVdWbXeYf..
。 X
是一个旧顶点,Y
是一个新顶点。创建一对新的半边g
和g
,它们将连接顶点V
和Y
。从链接列表中提取序列VdWbXeY
并向其添加g
以创建新的面[VdWbXeYg]
。添加半边h
以连接旧版面中的V
和Y
以生成..cVhYf..
。将新面孔标记为新面孔。如果没有更多的新顶点,我们就完成了。如果没有,请将名称..cVhYf..
映射到..cVdWb..
以进行迭代。
这种符号有点令人讨厌,但从概念上讲它很容易。三个步骤中的每一个都成对地添加半边缘;在步骤1中,通过划分边缘,在步骤2和3中添加它们。这些添加中的每一个都保持多面体表示的入射不变量不变,这意味着您可以改进代码中的修改局部性。