2008-12-12 10 views
4

J'ai besoin de créer un modèle 3D d'un cube avec un trou circulaire poinçonné au centre d'une face passant complètement à travers le cube du côté opposé. Je suis capable de générer les sommets pour les faces et les trous.Trou dans un polygone

Quatre des faces (non touchées par le trou) peuvent être modélisées comme une seule bande de triangle. L'intérieur du trou peut également être modélisé comme une seule bande de triangle.

Comment générer le tampon d'index pour les faces avec les trous? Existe-t-il un ou plusieurs algorithmes standard pour le faire? J'utilise Direct3D mais les idées d'ailleurs sont les bienvenues.

Répondre

4

Vous voulez rechercher Tessellation qui est le domaine des mathématiques qui traite de ce MizardX est showing.Folks dans graphcs 3D ont pour faire face à cela tout le temps et il existe une variété d'algorithmes de tessellation pour prendre un visage avec un trou et calculer les triangles nécessaires pour le rendre.

3

Le matériel moderne ne peut généralement pas rendre correctement les polygones concaves.
Plus précisément, il n'y a même pas moyen de définir un polygone avec un trou.
Vous devrez trouver une triangulation du plan autour du trou en quelque sorte. Le meilleur moyen est probablement de créer des triangles à partir d'un sommet du trou jusqu'aux sommets les plus proches de la face rectangulaire. Cela va probablement créer des triangles très fins. Si ce n'est pas un problème, alors vous avez terminé. Si c'est le cas, vous aurez besoin d'un algorithme de carénage/optimisation de maillage pour créer de beaux triangles.

3

L'alpha est-il hors de question? Sinon, il suffit de texturer les côtés avec des trous en utilisant une texture qui a la transparence au milieu. Vous devez faire plus de rendu de polygones car vous ne pouvez pas tirer avantage de dessiner de l'avant à l'arrière et ignorer les faces couvertes, mais cela peut être plus rapide que d'avoir beaucoup de minuscules triangles.

+0

Bonne idée! Mais dans mon cas, les choses sont un peu plus compliquées et je vais devoir utiliser un maillage. –

6

Pour générer le tampon d'index souhaité, vous pouvez procéder comme suit. Penser en 2D avec le visage en question comme un carré avec des sommets (& plusmn; 1, & plusmn; 1), et le trou comme un cercle au milieu.

  1. Vous marchez le long du bord du cercle, en le divisant en un certain nombre de segments.
  2. Pour chaque sommet, vous le projetez sur le carré environnant avec (x/M,y/M), où M est max(abs(x),abs(y)). M est la valeur absolue de la plus grande coordonnée, donc cette échelle sera (x,y) de sorte que la plus grande coordonnée est & plusmn; 1.
  3. Cette ligne vous divisez également en un certain nombre de segments.
  4. Les segments de deux lignes successives que vous rejoignez par paires en tant que faces.

Ceci est un exemple, subdivisant le cercle en 64 segments, et chaque rayon en 8 segments. Vous pouvez choisir les numéros correspondant à vos besoins.

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

Voici un code Python qui illustre ceci:

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() 
+0

MizardX, je n'ai pas bien compris "2. Pour chaque sommet, vous le projetez sur le carré environnant avec (x/M, y/M), où M est max (abs (x), abs (y))." Et comment avez-vous généré l'image? –

2

J'imagine 4 ventilateurs triangulaires provenant des 4 coins du carré.

1

Juste une pensée -

Si vous êtes dans la tricherie (comme cela se fait à plusieurs reprises dans les jeux), vous pouvez toujours construire un cube régulier, mais ont la texture pour les deux visages que vous désirez avec un trou (alpha = 0), vous pouvez soit le découper dans le shader, soit le mélanger (dans ce cas, vous devez effectuer un rendu avec le tri Z). Vous obtenez le trou intérieur en construisant un cylindre intérieur tourné vers l'intérieur et sans bouchon.

Bien sûr, cela ne fonctionnera que si la géométrie n'est pas importante pour vous.