0

我正在尝试找到一种算法来使用两个(或更多)剖面切割 3D 对象。仅应在两个剖面都被切割的地方切割对象。因此,考虑以下由两个剖面相交的 abcd 矩形:s0 和 s1;s1 向右切,s0 向顶部切。我想要的是得到最终的 ajikcd 形状。

.        |s1
. a______j_________b  ^
. |      |         |  |
. |- - - i - - - - |k- - s0
. |      |         |  
. d----------------c
.        |->

这是一个非常简单的例子,但我希望它能清楚地说明我想要完成的工作。此外,这应该在 3D 中完成。

有谁知道这样做的任何库,或这样做的算法?这似乎是一个重要的问题,一定有人在我之前解决了!:)

我必须补充一点,我知道如何做基础知识(平面与面/平面/边缘的相交)。我看不到是否有一种聪明的方法来解决所有可能的情况(在这个情况下,必须添加两个面,但在其他一些情况下可能只创建一个面,等等),或者你是否应该处理它们分别地。

我应该补充的另一件事是我不关心渲染部分,我知道如何使用带有剪裁平面的 OpenGL 来做到这一点。我想要的是能够计算对象的新拓扑。

4

1 回答 1

0

我认为这可以通过将对象切片,移除不需要的部分,然后通过合并面将剩余的部分重新粘合在一起来相当容易地解决。

假设您将对象建模为完全链接的图

  • 一个顶点列表,每个顶点都有一个边列表
  • 边列表,每条边都引用两个顶点和两个面
  • 面列表,每个面都有一个边列表

只要您小心维护和操作此图,它就会包含快速剪切和合并对象所需的所有信息。

您可以使用此答案中描述的算法来计算剪切产生的新面。

所以:您对算法的输入是切割平面列表和对象列表 - 最初只有一个。对于每个切割平面,将列表对象中的每个对象一分为二,然后将它们放回列表中。添加的两个面(每个新对象上一个)应保持对生成它们的切割平面的引用。对于被平面切成两半的面,请记住生成的两个新面应继承此参考(如果存在)。新对象应该记录它们位于平面的哪一侧(只是一个布尔值,意思是“保留”或“丢弃”)——这些记录也应该随着对象的进一步细分而保留。

完成所有切割后,您将获得一个对象列表,每个对象都有一个记录列表,详细说明它们位于切割平面的哪一侧。找到所有这些记录都“丢弃”的对象并将它们扔掉。

我们现在必须把这些物体粘在一起。

首先简单地合并对象图 - 只需将所有顶点、边和面列表组合到一个对象中。我们现在检查由同一切割平面创建的两个面:

  • 如果两个面相同(即:它们共享同一组顶点),则可以删除两个面和所有关联的边。
  • 如果一个面的顶点集大于另一个面,则删除较小的面和所有共享边。

您现在应该有一个合并的对象,但有一些无关的顶点。简单地遍历顶点并删除那些只有两条关联边的顶点。

这是切割如何工作的示例:

      :
a---1-:---b
|     :   |
2   X :   3
|     :   |
|     :   |
c---4-:---d
      :
      :s 

我们从一个对象开始(?表示未显示的某些边缘或面):

verts:
  a:1,2,?
  b:1,3,?
  c:2,4,?
  d:3,4,?
edges:
  1:a,b X,?
  2:a,c X,?
  3:b,d X,?
  4:c,d X,?
faces:
  X:1,2,3,4
  ?:...

当我们用平面 s 切割时,我们最终得到两个对象:

a--1--e-7-b
|     |   |
2  X  5 Y 3
|     6   |
|     |   |
c--4--f-8-d

verts:            verts:         
  a:1,2,?           e:1,5,6,7    
  e:1,5,6,7         b:3,7,?        
  c:2,4,?           d:3,8,?        
  f:4,5,6,8         f:4,5,6,8    
edges:            edges:         
  1:a,e X,?         3:b,d Y,?    
  2:a,c X,?         6:e,f Y,W    
  4:c,f X,?         7:e,b Y,?    
  5:e,f X,V         8:f,d Y,?    
faces:            faces:         
  X:1,2,3,4         Y:3,6,7,8    
  V:5,...           W:6,...      
  ?:...             ?:...

我们添加了顶点 e 和 f、边 5 和 6,以及面 V 和 W。请注意,边 5 和 6 是不同的对象,它们共享相同的顶点,但在不同的面之间。

当我们将这两个对象重新合并在一起时,我们首先简单地合并两个对象图:

verts:
  a:1,2,?
  b:3,7,?        
  c:2,4,?
  d:3,8,?
  e:1,5,6,7        
  f:4,5,6,8  
edges:
  1:a,e X,?         
  2:a,c X,?         
  3:b,d Y,?    
  4:c,f X,?         
  5:e,f X,V         
  6:e,f Y,W    
  7:e,b Y,?
  8:f,d Y,?    
faces:
  X:1,2,3,4
  Y:3,6,7,8    
  V:5,...           
  W:6,...      
  ?:...

我们可以看到面 V 和 W 是由相同的切割平面产生的并且具有相同的顶点集,因此可以将它们与关联的边一起删除。与一对重合边相关联的两个未移除的面被合并。

a--1--e-7-b
|         |
2  X      3
|         |
|         |
c--4--f-8-d

verts:
  a:1,2,?
  b:3,7,?        
  c:2,4,?
  d:3,8,?
  e:1,7        
  f:4,8  
edges:
  1:a,e X,?         
  2:a,c X,?         
  3:b,d X,?    
  4:c,f X,?    
  7:e,b X,?
  8:f,d X,?    
faces:
  X:1,2,3,4,7,8
  ?:...

然后我们可以删除只有两条关联边的顶点,并合并这些边:

verts:
  a:1,2,?
  b:1,3,?        
  c:2,4,?
  d:3,8,?
edges:
  1:a,e X,?         
  2:a,c X,?         
  3:b,d Y,?    
  4:c,d X,?
faces:
  X:1,2,3,4
  Y:3,6,7,8  
  ?:...

合并这些对象怎么样?

a--1--e
|     5   
2  X  g-3-b
|     6   |
|     9 Y 7
c--4--f-8-d

verts:            verts:         
  a:1,2,?           g:3,5,6,?    
  e:1,5,?           b:3,7,?        
  c:2,4,?           d:7,8,?        
  f:4,6,8,9,?       f:4,6,8,9,?
edges:            edges:         
  1:a,e X,?         3:b,g Y,?    
  2:a,c X,?         9:f,g Y,W    
  4:c,f X,?         7:b,d Y,?    
  5:e,g X,V,?       8:f,d Y,?    
  6:f,g X,V
faces:            faces:         
  X:1,2,4,5,6       Y:3,7,8,9
  V:5,6,...         W:9,...      
  ?:...             ?:...

我们合并:

verts:
  a:1,2,?    
  b:3,7,?               
  e:1,5,?           
  c:2,4,?           
  d:7,8,?        
  f:4,6,8,9,?         
  g:3,5,6,9,?    
edges:
  1:a,e X,?         
  2:a,c X,?         
  3:b,g Y,?    
  4:c,f X,?         
  5:e,g X,V,?         
  6:f,g X,V
  7:b,d Y,?    
  8:f,d Y,?    
  9:f,g Y,W    
faces:
  X:1,2,4,5,6
  Y:3,6,7,8    
  V:5,6,...
  W:9,...
  ?:...

并检查面 V 和 W,因为它们是由同一剖切面创建的。这次他们的顶点集是不同的。去掉小脸。在这两个面上,找到具有相同顶点的边并将它们删除:

a--1--e
|     5   
2  X  g-3-b
|         |
|         7
c--4--f-8-d

verts:
  a:1,2,?    
  b:3,7,?               
  e:1,5,?           
  c:2,4,?           
  d:7,8,?        
  f:4,8         
  g:3,5,?    
edges:
  1:a,e X,?         
  2:a,c X,?         
  3:b,g X,?    
  4:c,f X,?         
  5:e,g X,V,?
  7:b,d X,?    
  8:f,d X,?
faces:
  X:1,2,3,4,5,7,8
  V:5,...
  ?:...

我们现在可以删除只有两条入射边的无用顶点:

a--1--e
|     5   
2  X  g-3-b
|         |
|         7
c----4----d

verts:
  a:1,2,?    
  b:3,7,?               
  e:1,5,?           
  c:2,4,?           
  d:4,7,?   
  g:3,5,?    
edges:
  1:a,e X,?         
  2:a,c X,?         
  3:b,g Y,?    
  4:c,d X,?         
  5:e,g X,?
  7:b,d X,?
faces:
  X:1,2,3,4,5,7
  V:5,...
  ?:...

呸!希望这可以帮助...

于 2012-10-12T10:58:55.767 回答