Отверстие в многоугольнике - PullRequest
4 голосов
/ 12 декабря 2008

Мне нужно создать трехмерную модель куба с круглым отверстием, пробитым в центре одной грани, полностью проходящим через куб на противоположную сторону. Я могу генерировать вершины для граней и отверстий.

Четыре грани (нетронутые отверстием) можно смоделировать как одну треугольную полосу. Внутренняя часть отверстия также может быть смоделирована как одна треугольная полоса.

Как мне сгенерировать индексный буфер для граней с отверстиями? Существует ли стандартный алгоритм (ы) для этого?

Я использую Direct3D, но идеи из других стран приветствуются.

Ответы [ 6 ]

6 голосов
/ 12 декабря 2008

Чтобы сгенерировать индексный буфер, который вы хотите, вы можете сделать это следующим образом. Мышление в 2D с рассматриваемой гранью в виде квадрата с вершинами (& plusmn; 1, plusmn; 1) и дырой в виде круга в середине.

  1. Вы идете по краю круга, разделяя его на несколько сегментов.
  2. Для каждой вершины вы проецируете ее на окружающий квадрат с помощью (x/M,y/M), где M равно max(abs(x),abs(y)). M - это абсолютное значение самой большой координаты, поэтому она будет масштабироваться (x,y), так что самая большая координата будет равна & plusmn; 1.
  3. Эту линию вы также делите на некоторое количество сегментов.
  4. Сегменты двух последующих линий, которые вы соединяете попарно как лица.

Это пример, подразделяющий круг на 64 сегмента, а каждый луч на 8 сегментов. Вы можете выбрать номера в соответствии с вашими требованиями.

альтернативный текст 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()
4 голосов
/ 12 декабря 2008

Вы хотите посмотреть Тесселяцию, которая является областью математики, которая имеет дело с тем, что показывает MizardX. Сферы в 3D-графиках должны иметь дело с этим все время, и есть множество алгоритмов тесселяции, чтобы принять лицо с дырой и вычислите треугольники, необходимые для его рендеринга.

3 голосов
/ 12 декабря 2008

Может ли альфа смешиваться? Если нет, просто текстурируйте стороны с отверстиями, используя текстуру с прозрачностью в середине. Вы должны сделать больше рендеринга полигонов, так как вы не можете использовать преимущества рисования спереди назад и игнорирования закрытых граней, но это может быть быстрее, чем иметь много маленьких треугольников.

3 голосов
/ 12 декабря 2008

Современное оборудование обычно не может правильно отображать вогнутые полигоны.
В частности, обычно даже нет способа определить многоугольник с отверстием.
Вам нужно как-то найти триангуляцию плоскости вокруг отверстия. Наилучшим способом, вероятно, является создание треугольников от вершины отверстия до ближайших вершин прямоугольной грани. Это, вероятно, создаст несколько очень тонких треугольников. если это не проблема, то все готово. если это так, то вам потребуется алгоритм обтекания / оптимизации сетки для создания красивых треугольников.

2 голосов
/ 12 декабря 2008

Я представляю 4 треугольных веера, идущих из 4 углов квадрата.

1 голос
/ 15 февраля 2009

Просто мысль -

Если вы в мошенничестве (как это было много раз в играх), вы всегда можете построить обычный куб, но иметь текстуру для двух граней, которые вы хотите, с отверстием (альфа = 0), затем вы можете либо обрезать его в шейдере или смешайте его (в этом случае вам нужно визуализировать с помощью Z sort). Вы получите внутреннее отверстие, построив внутренний цилиндр, обращенный внутрь и без заглушек.

Конечно, это будет работать, только если геометрия не важна для вас.

...