gluTess函数背后的算法是什么?

时间:2012-10-12 04:00:09

标签: opengl tesselation

我出于好奇而问这个问题,出于性能原因,在使用GLU之前首先尝试实施这样的算法。

我研究了常见的算法(经常提到Delaunay,Ear Clipping),但我似乎无法理解GLU如何一直如此好地工作。

你们有没有关于这个问题的有趣论文或文章?

1 个答案:

答案 0 :(得分:14)

some notes旁边有the source

  

这只是一个非常简短的概述。有很多   源代码本身的其他文档。

     

稳健的细分目标

     

细分算法基本上是2D算法。我们   最初将所有数据投影到一个平面上;我们的目标是坚定不移   详细说明预计的数据。同样的拓扑结构是   然后应用于输入数据。

     

拓扑上,输出应始终是一个细分。如果   输入甚至是略微非平面的,然后是一些三角形   从某些角度来看,必然是背对面的,但目标   是为了尽量减少这种影响。

     

该算法需要一些清理输入数据的能力   以及自己计算中的数值误差。一种方法   这是指定上面定义的公差,并清理   线扫描过程中的输入和输出。至少,   算法必须处理重合顶点,顶点入射到一个顶点   边缘和重合边缘。

     

算法的阶段

     
      
  1. 找到多边形法线N。
  2.   
  3. 将顶点数据投影到平面上。它不需要垂直于法线,例如。我们可以投射到飞机上   垂直于坐标轴,其点积为N   最大。
  4.   
  5. 使用线扫描算法,将平面划分为x单调区域。任何垂直线与at中的x-单调区域相交   最多一个间隔。
  6.   
  7. 对x单调区域进行三角测量。
  8.   
  9. 将三角形分为条状和扇形。
  10.         

    查找法线向量

         

    查找多边形法线的常用方法是计算有符号区域   当多边形沿三个坐标轴投影时。我们   不能做到这一点,因为轮廓可以没有区域   退化(例如领结)。

         

    我们将平面拟合到顶点数据,忽略它们的连接方式   进入轮廓。理想情况下,这将是最小二乘拟合;但是对于   我们的目的是正常的准确性并不重要。相反,我们   找到三个分开的顶点,并计算法线   他们形成的三角形。选择顶点使得   三角形的面积至少是最大面积的1 / sqrt(3)倍   使用输入顶点形成的三角形。

         

    轮廓确实会影响正常的方向;经过计算   正常,我们检查签名轮廓区域的总和是   非阴性,必要时逆转正常。

         

    投影顶点

         

    我们将顶点投影到垂直于三者之一的平面上   坐标轴。这通过删除a来帮助提高数值   原始输入数据和数据之间的转换步骤   由算法处理。投影也会压缩输入   数据;投影后顶点之间的2D距离可以更小   比原来的2D距离。但是通过选择坐标   与正常的点积最大的轴,压缩   因子最多为1 / sqrt(3)。

         

    即使正常的准确度并不那么重要(因为   我们正在垂直于坐标轴投影)   计算的鲁棒性很重要。例如,如果有许多顶点几乎沿着一条线和一个顶点V   这是与行分开的,然后我们正常的计算   应该涉及V否则结果将是垃圾。

         

    垂直于多边形法线投影的优点是   计算出的交点将尽可能接近   他们理想的位置。要获得此行为,请定义TRUE_PROJECT。

         

    线扫描

         

    有三种数据结构:网格,事件队列和   边缘字典。

         

    网格是一个四边形"记录拓扑的数据结构   目前的分解;有关详细信息,请参阅包含文件" mesh.h"。

         

    事件队列只包含所有顶点(原始顶点和计算顶点)   组织,以便我们可以快速提取顶点   最小x-coord(其中,最小y-coord)。

         

    边缘字典描述了扫描的当前交集   与多边形区域对齐。这只是一个排序   与扫描线相交的边,按其当前顺序排序   路口。对于每对边缘,我们存储一些信息   他们之间的单调区域 - 这些是呼叫"活跃区域"   (因为它们被当前的扫描线穿过)。

         

    基本算法是从左向右扫描,处理每个   顶点。网格的处理部分(扫描线的左侧)是   平面分解。当我们穿过每个顶点时,我们更新网格   和边缘字典,然后我们检查任何新邻近的对   边缘,看它们是否相交。

         

    顶点可以有任意数量的边。具有许多边的顶点可以   在合并顶点和交叉点时创建   计算。对于未处理的顶点(扫描线的右侧),这些   边缘在顶点周围没有特定的顺序;用于处理   顶点,拓扑排序应与几何相匹配   排序

         

    顶点处理分两个阶段进行:首先我们处理的是   左边缘(所有这些边缘当前都在边缘   字典)。这包括:

         
        
    • 从字典中删除左边缘;
    •   
    • 根据需要重新链接网格,以使事件顶点周围的这些边的顺序与字典中的顺序匹配;
    •   
    • 将任何终止区域(位于两个左边缘之间的区域)标记为"内部"或"外面"根据   他们的蜿蜒数字。
    •   
         

    当没有左边缘时,事件顶点在   "室内"区域,我们需要添加一条边(将区域分割成   单调的片断)。为此,我们只需将事件顶点连接到   包含的上边缘或下边缘的最右端点   区域。

         

    然后我们处理正确的边缘。这包括:

         
        
    • 在边缘词典中插入边缘;
    •   
    • 计算任何新创建的活动区域的匝数。我们可以使用每个边缘的绕组来逐步计算   当我们走进字典时,我们就越过了。
    •   
    • 根据需要重新链接网格,以使事件顶点周围的这些边的顺序与字典中的顺序匹配;
    •   
    • 检查任何新近相邻的边以进行交叉和/或合并。
    •   
         

    如果没有右边缘,我们需要再加一个来分割   含有区域成单调的碎片。在我们的例子中它是最多的   方便的是将边添加到任一个的最左端点   包含边缘;但是我们可能需要稍后改变它(见   代码详情)。

         

    不变量

         

    这些是扫描期间保持的最重要的不变量。   我们定义了一个函数VertLeq(v1,v2),它定义了它的顺序   顶点穿过扫描线,并有一个函数EdgeLeq(e1,e2; loc)   这表示在扫描事件位置e1是否低于e2" loc"。   此功能仅在扫描事件位置定义   在最右边的左端点{e1,e2}和最左边的端点之间   {e1,e2}的终点。

         

    边缘词典的不变量。

         
        
    • 每对相邻边e2 = Succ(e1)在扫描事件的任何有效位置满足EdgeLeq(e1,e2)。
    •   
    • 如果EdgeLeq(e2,e1)也是(在任何有效的扫描事件中),那么e1和e2共享一个公共端点。
    •   
    • 对于字典中的每个e,e-> Dst已经处理但不是e-> Org。
    •   
    • 每个边e满足VertLeq(e-> Dst,event)&& VertLeq(event,e-> Org)其中" event"是当前的扫描线   事件
    •   
    • 没有边e的长度为零。
    •   
    • 没有两条边具有相同的左右端点。网格的不变量(已处理部分)。

    •   
    • 扫描线左侧的网格部分是平面图,即。有一些方法将它嵌入到平面中。

    •   
    • 没有处理过的边长度为零。
    •   
    • 没有两个处理过的顶点具有相同的坐标。
    •   
    • 每个"内部"区域是单调的,即。可以根据VertLeq(v1,v2)分成两个单调增加顶点的链      
          
      • 非不变量:这些链可能会(略微)相交   数值误差,但这不会影响算法的运算。
      •   
    •   
         

    扫描的不变量。

         
        
    • 如果顶点有任何左边缘,那么这些顶点处理时必须在边缘字典中。
    •   
    • 如果标记边缘" fixUpperEdge" (这是ConnectRightVertex引入的临时优势),那么它是唯一正确的   边缘来自其关联的顶点。 (这说明存在这些边缘   只有在必要的时候。)
    •   
         

    鲁棒性

         

    算法的鲁棒性的关键是保持   上面的不变量,特别是边的正确排序   字典。我们通过以下方式实现这一目标:

         
        
    1. 编写数值计算以获得最大精度    比最高速度。

    2.   
    3. 根本没有对边缘结果做出任何假设    交叉计算 - 对于充分退化的输入,    计算出的位置并不比随机数好多了。

    4.   
    5. 当数字错误违反不变量时,请恢复它们    通过在必要时进行拓扑更改(即重新链接)    网格结构)。

    6.         

      三角测量和分组

           

      我们在进行任何三角测量之前完成线扫描。这是   因为即使在单调区域完成之后,也可以进一步发展   由于进一步的顶点合并,它的顶点数据发生了变化。

           

      在对所有单调区域进行三角测量之后,我们想要对这些区域进行分组   三角形成扇形和条形。我们使用贪婪的方法来做到这一点。   三角测量本身并未优化以减少数量   元;我们只是试图得到一个合理的分解   计算三角测量。