【问题标题】:Hole in a Polygon多边形中的孔
【发布时间】:2010-09-26 14:13:54
【问题描述】:

我需要创建一个立方体的 3D 模型,在一个面的中心打一个圆孔,完全穿过立方体到另一侧。我能够为面和孔生成顶点。

其中四个面(未受孔影响)可以建模为单个三角形带。孔的内部也可以建模为单个三角形条带。

如何为有孔的面生成索引缓冲区?是否有标准算法来执行此操作?

我正在使用 Direct3D,但欢迎来自其他地方的想法。

【问题讨论】:

    标签: algorithm graphics 3d geometry


    【解决方案1】:

    只是一个想法-

    如果您喜欢作弊(就像在游戏中多次做的那样),您始终可以构建一个常规立方体,但具有您想要的带有孔的两个面的纹理 (alpha = 0),然后您可以将其剪掉在着色器中,或混合它(在这种情况下,您需要使用 Z 排序进行渲染)。 您可以通过构造一个朝内且没有盖帽的内圆柱体来获得内孔。

    当然,这只有在几何形状对您不重要时才有效。

    【讨论】:

      【解决方案2】:

      要生成您想要的索引缓冲区,您可以这样做。在 2D 中思考问题的脸是一个顶点为 (±1, ±1) 的正方形,而洞是中间的一个圆。

      1. 您沿着圆的边缘行走,将其分成若干段。
      2. 对于每个顶点,使用(x/M,y/M) 将其投影到周围的正方形上,其中Mmax(abs(x),abs(y))M 是最大坐标的绝对值,所以这将缩放(x,y),使最大坐标为±1。
      3. 您还可以将这条线分成若干段。
      4. 您成对连接的两条连续线的线段作为面。

      这是一个示例,将圆细分为 64 段,每条射线分为 8 段。您可以选择符合您要求的数字。

      alt text http://pici.se/pictures/AVhcssRRz.gif

      下面是一些演示这一点的 Python 代码:

      from math import sin, cos, pi
      from itertools import izip
      
      def pairs(iterable):
          """Yields the previous and the current item on each iteration.
          """
          last = None
          for item in iterable:
              if last is not None:
                  yield last, item
              last = item
      
      def circle(radius, subdiv):
          """Yields coordinates of a circle.
          """
          for angle in xrange(0,subdiv+1):
              x = radius * cos(angle * 2 * pi / subdiv)
              y = radius * sin(angle * 2 * pi / subdiv)
              yield x, y
      
      def line(x0,y0,x1,y1,subdiv):
          """Yields coordinates of a line.
          """
          for t in xrange(subdiv+1):
              x = (subdiv - t)*x0 + t*x1
              y = (subdiv - t)*y0 + t*y1
              yield x/subdiv, y/subdiv
      
      def tesselate_square_with_hole((x,y),(w,h), radius=0.5, subdiv_circle=64, subdiv_ray=8):
          """Yields quads of a tesselated square with a circluar hole.
          """
          for (x0,y0),(x1,y1) in pairs(circle(radius,subdiv_circle)):
              M0 = max(abs(x0),abs(y0))
              xM0, yM0 = x0/M0, y0/M0
      
              M1 = max(abs(x1),abs(y1))
              xM1, yM1 = x1/M1, y1/M1
      
              L1 = line(x0,y0,xM0,yM0,subdiv_ray)
              L2 = line(x1,y1,xM1,yM1,subdiv_ray)
              for ((xa,ya),(xb,yb)),((xc,yc),(xd,yd)) in pairs(izip(L1,L2)):
                  yield ((x+xa*w/2,y+ya*h/2),
                         (x+xb*w/2,y+yb*h/2),
                         (x+xc*w/2,y+yc*h/2),
                         (x+xd*w/2,y+yd*h/2))
      
      
      import pygame
      def main():
          """Simple pygame program that displays the tesselated figure.
          """
          print('Calculating faces...')
          faces = list(tesselate_square_with_hole((150,150),(200,200),0.5,64,8))
          print('done')
      
          pygame.init()
          pygame.display.set_mode((300,300))
          surf = pygame.display.get_surface()
          running = True
      
          while running:
              need_repaint = False
              for event in pygame.event.get() or [pygame.event.wait()]:
                  if event.type == pygame.QUIT:
                      running = False
                  elif event.type in (pygame.VIDEOEXPOSE, pygame.VIDEORESIZE):
                      need_repaint = True
              if need_repaint:
                  print('Repaint')
                  surf.fill((255,255,255))
                  for pa,pb,pc,pd in faces:
                      # draw a single quad with corners (pa,pb,pd,pc)
                      pygame.draw.aalines(surf,(0,0,0),True,(pa,pb,pd,pc),1)
                  pygame.display.flip()
      
      try:
          main()
      finally:
          pygame.quit()
      

      【讨论】:

      • MizardX,我没有完全理解“2。对于每个顶点,你用 (x/M,y/M) 将它投影到周围的正方形上,其中 M 是 max(abs(x),绝对(y))。”您是如何生成图像的?
      【解决方案3】:

      我想象 4 个三角形风扇从广场的 4 个角落飞来。

      【讨论】:

        【解决方案4】:

        您想查找 Tessellation,这是处理 MizardX 所显示内容的数学领域。3D Graphcs 中的人们必须一直处理这个问题,并且有多种 tessellation 算法来获取带孔的面部并计算渲染它所需的三角形。

        【讨论】:

          【解决方案5】:

          Alpha 混合是不可能的吗?如果没有,只需使用中间具有透明度的纹理对带有孔的侧面进行纹理处理。你必须做更多的多边形渲染,因为你不能利用从前到后绘制和忽略覆盖面的优势,但它可能比有很多小三角形更快。

          【讨论】:

          • 好主意!但就我而言,事情有点复杂,我将不得不使用网格。
          【解决方案6】:

          现代硬件通常无法正确渲染凹多边形。
          具体来说,通常甚至没有办法定义带孔的多边形。
          您需要以某种方式在孔周围找到平面的三角剖分。最好的方法可能是创建从孔的顶点到矩形面最近顶点的三角形。这可能会创建一些非常薄的三角形。如果这不是问题,那么你就完成了。如果是这样,那么您将需要一些网格整流/优化算法来创建漂亮的三角形。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-10-14
            • 1970-01-01
            • 2017-12-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多